Vue3的Diff算法

288 阅读2分钟

Vue3的Diff算法

oldVnode = [a,b,c,d,e,f]
newVnode = [a,e,c,b,d,f]

1. 从前往后比较,当节点不同时,不再往后进行比较。

var oldVnode1 = [b,c,d,e,f]
var newVnode1 = [e,c,b,d,f]
var i = 1

2. 从后往前比较,当节点不同时,不再往前进行比较。

var oldVnode2 = [b,c,d,e]
var newVnode2 = [e,c,b,d]
var oldLen2 = 4
var newLen2 = 4

3. 利用“最长递增子序列”,完成上述差异部分的比较

3.1 仅有节点新增

3.2 仅有节点移除

3.3 有节点移动、新增或删除

3.3.1 对newVnode待处理节点的key和下标建立一个映射(key:index),目的是为了快速确认oldVnode待处理节点在newVnode待处理节点中是否有对应的节点及所在位置。

3.3.2 遍历oldVnode中待处理节点,判断newVnode中是否有相同key的节点存在。

3.3.2.1 没有,说明该节点已经被移除,unmount
3.3.2.2 有,则:
  • 调用patch函数,最终将旧节点的内容替换成新节点的内容。

  • 记录节点在newVnode和oldVnode中的位置关系

var newIndexToOldIndexMap = new  Array(newLen2).fill(0)
for(var index = i; index < oldLen2; index ++){
    var newIndex = newVnode.indexOf(oldVnode[index])
    if(newIndex > -1){
         newIndexToOldIndexMap[newIndex - i] = index + 1 
    }
   
}
// 第一次循环,oldVnode2的第一个元素:b, newVnode中对应得b的下标newIndex为2,则newIndexToOldIndexMap[2] = index + 1 = 1+1 = 2
// 第二次循环,oldVnode2的第一个元素:c, newVnode中对应得b的下标newIndex为1,则newIndexToOldIndexMap[1] = index + 1 = 2+1 = 3
// 第三次循环,oldVnode2的第一个元素:d, newVnode中对应得b的下标newIndex为3,则newIndexToOldIndexMap[3] = index + 1 = 3+1 = 4
// 第四次循环,oldVnode2的第一个元素:d, newVnode中对应得b的下标newIndex为3,则newIndexToOldIndexMap[0] = index + 1 = 4+1 = 5
// 顾newIndexToOldIndexMap = [5,3,2,4]
  • 计算newIndexToOldIndexMap的“最长递增子序列”
[5,3,2,4]的最长递增子序列为increasingNewIndexSequence =  [3,4]
  • 如果位置有移动,则移动newIndexToOldIndexMap中非 最长递增子序列的元素, 即移动[5,2]
// 从右到左遍历newVnode2  [e,c,b,d]
for(var index = newLen2-1; index>=0; index-- ){
    if(newIndexToOldIndexMap[index] === 0){
        var curVnode = newVnode[index + i]
        var nextVnode = newVnode[index + i + 1]
    // 旧节点找不到对对应得新节点,则为新增节点
    // 找到当前节点的下一个节点在页面上的位置,然后将待添加节点插入到下一个节点前面
    }else{
    // 如果属于最长递增子序列,则不需要移动
       if(increasingNewIndexSequence.indexOf(newIndexToOldIndexMap[index]) === -1){
       }else{
           // 如果不属于最长递增子序列,则需要移动
           // 移动的方式为 查找当前节点的下一个节点在页面上的位置,然后将当前节点移动到下一个节点前面;
           // 因为是从右到左遍历,顾下一个节点已经移动到正确的位置上了
           
       }
    }
}