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的写法。框架

第一次写文章,不足之处还请海涵
相关文章
相关标签/搜索