博客 / 詳情

返回

vue虛擬dom diff

虛擬元素節點VNode
什麼是虛擬元素節點?
虛擬元素節點即對真實dom節點的描述。包含標籤名、標籤屬性描述對象、子節點集合。
// example
{
    tag:'div'
    props:{
        key:'uuid',//VNode唯一key,新舊VNode diff時有用
        id:'div',//VNode id值
        //...
    }
}
virtual dom優勢?
不用直接操作dom,虛擬DOM具有批處理和高效的Diff算法,可以減少重排與重繪,提高性能;virtual dom是javascript對象,具有跨平台優勢;
virtual dom diff思路
  • VNode變化類型:
REPLACE:當前節點節點替換。比較方式:同一位置新舊節點一一對比。結構:{type:0,node:newNode}。
REORDER:子節點集合中新增、刪除的子節點。比較方式:子節點集合同級對比。結構:{type:1,moves:[{type:0——刪除,index:該子節點在子節點集合中的下標},{type:1——新增,index:該子節點在子節點集合中的下標,item:newVNode}]}。
PROPS:當前節點屬性變化。比較方式:同一位置新舊節點一一對比。結構:{type:2,props:[{修改propKey:undefined——刪除該屬性,propKey:newPropValue}]}。
TEXT:當前節點文本節點變化。比較方式:同一位置新舊節點一一對比。結構:{type:3,content:newText}。
  • 新舊虛擬dom diff思路總結:由於跨級修改很少,可忽略不計,所以僅進行同級子節點集合對比。
    注意:新舊虛擬dom diff對比時,採用遞歸方法,並且從上往下統計。

    • 對比結果存放patches[key]:key為virtual dom tree遞歸時節點所處的位置,便於在patch應用在actual dom tree時,能準確找到對應的節點。
    • 先進行newVNodeList與oldVNodeList中同位置(同index)的VNode對比,統計VNode的props、text,VNode被替換(標籤名或VNode唯一key不一致)的改變
    • 再進行同級childVNodeList對比,統計子節點刪除、新增情況。並且返回含oldVNodeList.length長度和newVNodeList中VNode/Text值的新數組。通過VNode唯一key進行對比統計。
對比結果patches,應用到真實dom

注意:將對比結果patches,應用到真實dom時,採用遞歸方法,並且從下往上應用。

  • patch.type===0(替換節點):node.parentNode.replaceChild(newNode,oldNode)
  • patch.type===1(刪除、新增子節點): removeChild(removeNode)、cloneNode(true)、insertBefore(insertNode,beforeNode)
  • patch.type===2(props變化):removeAttribute(prop)、setAttribute(prop)
  • patch.type===3(text變化):elementNode.textContent、textNode.nodeValue

參考網站:
深度剖析:如何實現一個 Virtual DOM 算法:https://github.com/livoras/blog/issues/13
同級VNodeList第一次對比代碼:https://github.com/livoras/list-diff/blob/master/lib/diff.js

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.