<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # Virtual Dom ## "昂貴"的DOM 我們可以做個試驗。打印出一個空元素的第一層屬性,可以看到標準讓元素實現的東西太多了。如果每次都重新生成新的元素,對性能是巨大的浪費。 ![](http://p878i6l4k.bkt.clouddn.com/%22%E6%98%82%E8%B4%B5%22%E7%9A%84DOM.png) #### Virtual Dom就是解決這個問題的一個思路,到底什么是Virtual Dom呢? >通俗易懂的來說就是用一個簡單的JS對象去代替復雜的dom對象。 舉個簡單的例子,我們在body里插入一個class為a的div。 ```js var mydiv = document.createElement('div'); mydiv.className = 'a'; document.body.appendChild(mydiv); ``` 對于這個div我們可以用一個簡單的對象VNode代表它,它存儲了對應dom的一些重要參數,在改變dom之前,會先比較相應虛擬dom的數據,如果需要改變,才會將改變應用到真實dom上。 ```js //偽代碼 var VNode = { tagName: 'DIV', className: 'a' }; mydiv.className = 'b'; // 改變class屬性 var oldVNode = VNode var newVNode = { tagName: 'DIV', className: 'b' } if(oldVNode.tagName !== newVNode.tagName || oldVNode.className !== newVNode.className){ patch(mydiv) } ``` #### 讀到這里就會產生一個疑問,為什么不直接修改dom而需要加一層Vrtual Dom呢? > 很多時候手工優化dom確實會比virtual dom效率高,對于比較簡單的dom結構用手工優化沒有問題,但當頁面結構很龐大,結構很復雜時,手工優化會花去大量時間,而且可維護性也不高,不能保證每個人都有手工優化的能力。 > 至此,Vrtual Dom的解決方案應運而生,Vrtual Dom很多時候都不是最優的操作,但它具有普適性,在效率、可維護性之間達平衡。 ## Vrtual Dom更新過程的實現 > 網上有太多的人講Vrtual Dom的實現過程。特別是其中的diff算法。但是,對于新手來說,這些文章會讓你似懂非懂。 > 我覺得最主要的原因是沒有對`key`這個屬性進行很好的解釋。 首先介紹兩個相關概念 ### diff 算法 VDom因為是純粹的JS對象,所以操作它會很高效,但是VDom的變更最終會轉換成DOM操作,為了實現高效的DOM操作,一套高效的虛擬DOM diff算法顯得很有必要。 先看整體視圖,整個diff分兩部分: ![](http://p878i6l4k.bkt.clouddn.com/diff%E7%AE%97%E6%B3%95.png) #### (一)、優先處理特殊場景 (1)、頭部的同類型節點、尾部的同類型節點 >這類節點更新前后位置沒有發生變化,所以不用移動它們對應的DOM (2)、頭尾/尾頭的同類型節點 >這類節點位置很明確,不需要再花心思查找,直接移動DOM就好 處理了這些場景之后,一方面一些不需要做移動的DOM得到快速處理,另一方面待處理節點變少,縮小了后續操作的處理范圍,性能也得到提升 #### (二)、“原地復用” 原地復用”是指Vue會盡可能復用DOM,盡可能不發生DOM的移動。 > Vue在判斷更新前后指針是否指向同一個節點,其實不要求它們真實引用同一個DOM節點,實際上它僅判斷指向的是否是同類節點(比如2個不同的div,在DOM上它們是不一樣的,但是它們屬于同類節點),如果是同類節點,那么Vue會直接復用DOM,這樣的好處是不需要移動DOM。 #### (三)、 ### key屬性在列表渲染中的作用 **官方解釋:** > 當 Vue.js 用 v-for 正在更新已渲染過的元素列表時,它默認用“就地復用”策略。如果數據項的順序被改變,Vue 將不會移動 DOM 元素來匹配數據項的順序, 而是簡單復用此處每個元素,并且確保它在特定索引下顯示已被渲染過的每個元素。這個類似 Vue 1.x 的 track-by="$index" 。 > 為了給 Vue 一個提示,以便它能跟蹤每個節點的身份,從而重用和重新排序現有元素,你需要為每項提供一個唯一 key 屬性。理想的 key 值是每項都有的且唯一的 id。這個特殊的屬性相當于 Vue 1.x 的 track-by ,但它的工作方式類似于一個屬性,所以你需要用 v-bind 來綁定動態值 我對官方的提煉: * 節點識別 * “原地復用”策略 * 默認類似 track-by="$index" #### 下面將從列表元素的渲染更新過程來介紹Vrtual Dom更新過程 ![](http://p878i6l4k.bkt.clouddn.com/%E8%99%9A%E6%8B%9FDOM-1.png) Vue分為在oldVDom樹設置oldStart和oldEnd指針,為newVDom樹設置newStart和newEnd指針。如下圖所示: ![](http://p878i6l4k.bkt.clouddn.com/%E8%99%9A%E6%8B%9FDOM-2.png) 新、舊虛擬DOM樹比較的的過程就是調用patch函數,就像打補丁一樣修改真實dom。同時,修改相應指針的指向,使其循環遍歷所有同層節點。 ``` // 偽代碼 function patch() { if (oldVNode.key === newVNode.key) { // 如果兩VNode節點的身份標識符相同(key) // 則對oldVNode進行更新操作 updateChildren(oldVNode, newVNode); } else if ( vnode.el === oldVnode.el) { // 如果兩VNode節點屬于同類型 // 則對oldVNode進行復用操作 patchVnode(oldVNode, newVNode) } else if (!oldVNode.el && newVNode.el) { // 如果oldVNode中不存在,newVNode中存在 // 則對oldVNode執行插入操作 const oEl = oldVnode.el let parentEle = api.parentNode(oEl) let newDom = createEle(vnode) api.insertBefore(parentEle, newDom, api.nextSibling(oEl)) } else if (oldVNode.el && !newVNode.el) { // 如果oldVNode中存在,newVNode中不存在 // 則對oldVNode執行刪除操作 let parentEle = api.parentNode(oEl) api.removeChild(parentEle, oldVnode.el) } } ``` 具體過程如下圖所示 ![](http://p878i6l4k.bkt.clouddn.com/%E8%99%9A%E6%8B%9FDOM-3.png) 最后patch過程為 ![](http://p878i6l4k.bkt.clouddn.com/%E8%99%9A%E6%8B%9FDOM-4.png) 可以看到: > 對A、B節點進行更新; > 對C、D節點進行復用; > 插入D節點。 顯然,更新的性能損耗要小于復用。因此,這樣的更新效率是比較低的。但是,這就是diff 算法的“原地復用”策略。 現在我們來看看當存在key屬性是的patch過程 設置key和不設置key的區別: > 不設key,oldVNode和newVNode只會進行頭尾兩端的相互比較,設key后,除了頭尾兩端的比較外,還會從用key生成的對象`oldKeyToIdx`中查找匹配的節點。 ```js oldKeyToIdx = createKeyToOldIdx(oldVNode, oldStart, oldEnd) // 有key生成index表 idxInOld = oldKeyToIdx[newStart.key] ``` > 所以為節點設置key可以更高效的利用dom。 ![](http://p878i6l4k.bkt.clouddn.com/%E8%99%9A%E6%8B%9FDOM-5.png) 可以看到: > 對A、B、C、D節點進行更新; > 在正確的位置插入F節點; 通過虛擬DOM計算出兩顆虛擬DOM樹之間的差異后,我們就可以用盡可能小的代價修改真實的DOM樹結構。在效率、可維護性之間達平衡。 至此,關于Vue的虛擬DOM的內容講完了,想更加深入了解的可以直接看源碼。我相信你看懂我這篇文章再看源碼應該難度會小很多。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看