virtual-dom內對children進行比較的list-diff的詳解

不清楚virtual-dom的能夠查看此文章vue

list-diff的源代碼react

前言:

在vue或者react內,每個VNode都有一個惟一key來標識,一般是框架自動處理,可是在循環內必須由開發者指定。因此如下解讀我就是用這個key來表明list內的對象。git

咱們並不須要真的達到最小的操做,咱們只須要優化一些比較常見的移動狀況,犧牲必定DOM操做,讓算法時間複雜度達到線性的(O(max(M, N))github

方法入口

let diff = (oldList, newList) => {
    let moves = [];
    // 邏輯處理
    return moves;
}

由上能夠看出,diff函數返回的是將舊數組轉換成新數組的步驟
下面我會詳細說明中間的邏輯處理步驟算法

咱們傳入兩個數組

oldList = [ A, B, C, D];
newList = [ E ,C, D, B];

第一步,兩個數組取交集,找到須要刪除的item

var simulateList = [];
oldList.forEach((item, index) => {
    // 此item存在於newList內
    if (newList.indexOf(item) !== -1) {
        simulateList.push(item)
    } else {
        moves.push({
            type: 'remove',
            index: index
        })
    }
});

// 程序運行結束,此時simulateList 就是oldList與newList的交集,而且是按oldList的順序進行排序的
// 此時simulateList的值爲[ B, C, D]
// 此時moves的值爲[{type:'remove',index:0}],標識將下標爲0的item從oldList內刪除,即刪除A

第二步,同步遍歷newList和simulateList

newList = [E,C,D,B];
simulateList= [B,C,D];

// i與j分別是newList與simulateList的下標

// newList E 與 simulateList B 比較,E 不等於 B 且 E 不存在於simulateList中,則insert E 
// 此時i=0;j=0;
moves = [
    {type:'remove',index:0},
    {type:'insert',index:0,item:E}
];
i++;

// newList C 與 simulateList B 比較,C 不等於 B 且 simulateList B 的下一個爲 C,則remove B
// i=1;j=0;

moves = [
    {type:'remove',index:0},
    {type:'insert',index:0,item:E},
    {type:'remove',index:1}
]
i++;
j++;


// 4. newList D 與 simulateList D 比較,相等則進入下一步比較
i++;
j++;

// 5. newList B,此時simulateList 已經比較完了,則 insert B
// i=3;j=2;

moves = [
    {type:'remove',index:0},
    {type:'insert',index:0,item:E},
    {type:'remove',index:1},
    {type:'inser', item: B, index: 3}
]

最終返回的數據如上所示,按照這個步驟,能夠將oldList轉變爲newList,一般狀況下對於list的改變主要集中在,刪除數據,或者新增數據,將list數據所有打亂的狀況極少,因此以上算法基本知足咱們的須要。數組

由上能夠看出惟一key的重要性,在用vue或者react寫list的時候,務必要使用惟一的固定值做爲能夠,杜絕用數組下標做爲key的寫法。框架

第一次寫文章,不足之處還請海涵
相關文章
相關標籤/搜索