手擼一個虛擬DOM

      網友投稿 929 2025-04-01

      什么是DOM


      手擼一個虛擬DOM

      DOM(文檔對象模型)是一種樹狀結構,包含有關 HTML(或 XML)頁面結構的信息。樹中的每個單獨的節點代表網頁上的一個元素。

      在 Javascript 中,可以通過window.document對象訪問和修改 DOM。讓我們看看如何使用 DOM 接口向網頁添加元素。

      我們有下面HTML模板代碼。

      DOM

      PS: 寫過Vue項目的同學可能比較熟悉,在Vue腳手架生成的項目中,public文件夾下的index.html也是定義了一個div#app.

      要通過 DOM 接口更改頁面的內容,我們可以執行以下操作:

      const app = document.querySelector('#app'); app.innerHTML = `

      Hello from DOM

      `;

      首先,我們從 DOM 中獲取一個 id 為“app”的元素,然后我們更改該元素的內容。

      這種修改DOM的方法,在以前是我們經常使用的,尤其是JQuery時代。這種方式適用于不經常更新UI的小型應用程序,如果我們想要構建一個高響應的網站,這種方法就會出現問題。

      JS操作DOM 是很慢的。每次都重新創建整棵樹會浪費時間和資源。如果我們想構建一個高反應性的網頁,我們需要尋找另一種解決方案。

      一種方法是通過比較新舊樹來查看哪些元素需要更新。這正是 Virtual DOM 的目標。

      創建一個虛擬 DOM

      在真實的 DOM 中,有一個document.createElement創建新節點的方法。對于我們的虛擬 DOM,我們也需要這樣一個方法。

      view方法

      讓我們創建一個名為h(約定)的函數

      const h = (type, props={}, children=[]) => ({ type, props, children, });

      type參數描述了 HTML 元素的類型,例如h1,div等等…

      props參數的工作方式與 React/Vue 中的 props 完全相同——它允許我們將數據(屬性)傳遞給元素

      children當前元素內其他子節點。

      讓我們看看它是如何使用的。

      const view = () => h('div', {}, [ h('h1', {}, ['Hello']), h('p', {}, ['from virtual DOM!']), h('p', {}, ['from virtual DOM!']), h('p', {}, ['from virtual DOM!']), h('p', {}, ['from virtual DOM!']), ]);

      我們創建了一個div元素,里面有h1和p元素。這些元素中的每一個都有一個文本節點作為其子節點。

      現在是時候將這個虛擬樹轉換為實際的 DOM。

      render方法

      讓我們實現一個render功能。

      const render = (root, view) => { const rendered = view(); diff(root, null, rendered); }; const diff = (root, oldNode, newNode, index) => { // 判斷節點是否變化,有變化則更新 }; render(app, view);

      渲染函數首先調用view函數,然后運行 diff 函數,該函數接受一個根元素(來自真實 DOM)、舊的虛擬節點(因為我們第一次渲染它是null)和新的虛擬節點 。

      diff方法

      基本上,該diff函數只會將 oldNode 與 newNode 進行比較,看看它是否需要更新root.

      現在讓我們看看如何實現 diff 函數。

      const diff = (root, oldNode, newNode, index) => { // 判斷節點是否變化,有變化則更新 if (!oldNode) { root.appendChild(createElement(newNode)); } };

      如果沒有oldNode,我們需要創建這個元素并將其插入 DOM。首先,我們使用該函數創建一個元素createElement,然后我們在第二個實現該函數,然后我們appendChild在一個真實的 DOM 元素上使用該方法,將該節點附加為其子節點。

      讓我們實現createElement功能。

      const createElement = (node) => { if (typeof node === 'string') { return document.createTextNode(node); } const el = document.createElement(node.type); node.children.map(createElement).forEach(el.appendChild.bind(el)); return el; };

      如果一個節點是一個文本節點(例如“Hello”),我們只需使用document.createTextNode函數渲染它。

      如果不是,我們創建給定類型的元素,document.createElement然后循環遍歷它的每個子元素,createElement遞歸調用函數。這樣我們就創建了整個樹并返回它。

      讓我們看看到目前為止我們編寫的完整代碼:

      const app = document.querySelector('#app'); const h = (type, props = {}, children = []) => ({ type, props, children, }); const view = () => h("div", {}, [ h("h1", {}, ["Hello"]), h("p", {}, ["from virtual DOM!"]), h("p", {}, ["from virtual DOM!"]), h("p", {}, ["from virtual DOM!"]), h("p", {}, ["from virtual DOM!"]), ]); const render = (root, view) => { const rendered = view(); diff(root, null, rendered); }; const diff = (root, oldNode, newNode, index) => { // 判斷節點是否變化,有變化則更新 if (!oldNode) { root.appendChild(createElement(newNode)); } }; const createElement = (node) => { if (typeof node === 'string') { return document.createTextNode(node); } const el = document.createElement(node.type); node.children.map(createElement).forEach(el.appendChild.bind(el)); return el; }; render(app, view);

      現在,在瀏覽器中,我們可以檢查我們的應用程序是否正常工作 - 如果我們運行此代碼,我們將看到以下內容:

      結論

      耶。現在使用view和h函數,我們可以構建無限復雜的 UI。

      當然,我們還沒有實現狀態管理,所以我們不能改變 DOM 中的任何東西。而且我們沒有將任何屬性傳遞給 DOM,因此我們無法真正設置應用程序的樣式。這個我們會在下一篇文章中繼續實現!

      虛擬化

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:強大高效而精簡易用的Golang爬蟲框架Colly,能否取代 Scrapy?
      下一篇:云速建站】讓你輕輕松松建立屬于自己的網店
      相關文章
      亚洲AV无码专区日韩| 青青青亚洲精品国产| 国产亚洲一区区二区在线| 久久无码av亚洲精品色午夜| 亚洲AV日韩综合一区尤物 | 亚洲日本乱码在线观看| 爱情岛论坛网亚洲品质自拍| 亚洲第一黄色网址| 亚洲一级Av无码毛片久久精品 | 亚洲一区二区影院| 久久亚洲AV成人无码电影| 亚洲视频免费在线看| 亚洲乱码一二三四五六区| 国产v亚洲v天堂a无| 亚洲欧美日韩综合俺去了| 亚洲风情亚Aⅴ在线发布| mm1313亚洲国产精品无码试看| 久久亚洲精品无码av| 亚洲AV无码乱码在线观看牲色| 亚洲人成无码www久久久| 国产亚洲精品久久久久秋霞| 亚洲精品国产成人片| 亚洲AV日韩AV天堂久久| 亚洲综合在线成人一区| 亚洲一本之道高清乱码| 亚洲中文字幕无码久久| 国产成人精品日本亚洲语音| 亚洲成av人片不卡无码久久| 国产日产亚洲系列| 无码久久精品国产亚洲Av影片| 亚洲人成电影在线天堂| 亚洲一区二区三区四区视频| 最新亚洲精品国偷自产在线| 国产精品亚洲一区二区在线观看| 亚洲一区二区精品视频| 久久精品夜色国产亚洲av| 亚洲国产精品综合久久久| 亚洲色精品三区二区一区| 国产亚洲精品免费| 亚洲欧洲精品无码AV| 亚洲一区免费观看|