10 双端比较
10.1 双端比较的原理
双端比较通过定义新旧节点的开始下标与结束下标四个变量。然后进行对比
- 新节点开始下标的节点和旧节点开始下标的节点对比
- 新节点结束下标的节点和旧节点结束下标的节点对比
- 新节点结束下标的节点和旧节点开始下标的节点对比
- 新节点开始下标的节点和旧节点结束下标的节点对比

代码如下
1 | function patchKeyedChildren(n1,n2,container){ |
处理新增和删除情况
处理在循环内部
在while循环中增加一个else处理在新节点在旧节点的情况
1
2
3
4
5
6
7
8
9
10
11
12
13const idxInOld = oldChildren.findIndex(node => node.key === newStartVNode.key)
if(idxInOld > 0) {
patch(oldChildren[idxInOld],newStartVNode,container)
// 将元素移动到最前面
insert(oldChildren[idxInOld].el,container, oldStartVNode.el)
// 由于idxInOld 对应元素已经移动 所以需要将原来的位置对应元素置为undefined
oldChildren[idxInOld] = undefined
newStartVNode = newChildren[++newStartIdx]
} else {
// 将newStartVNode作为新节点挂载到头部,使用当前头部节点 oldStartVNode.el作为锚点
patch(null,newStartVNode,container)
newStartVNode = newChildren[++newStartIdx]
}因为旧节点可能出现undefined情况,因此需要跳过旧节点为假的情况,需要在循环内最前面添加判断
1
2
3
4
5if(!oldStartVNode) {
oldStartVNode = oldChildren[++oldStartIdx]
} else if(!oldEndVNode) {
oldEndVNode = oldChildren[--oldEndIdx]
}处理循环外部的新增和删除情况
首先看新增情况,如果新节点开始下标小于新节点结束下标,因此在循环后面增加判断
1
2
3
4
5if(newStartIdx <= newEndIdx && oldStartIdx > oldEndIdx) {
for(let i = newStartIdx; i <= newEndIdx;i++) {
patch(null,newChildren[i],container, oldStartVNode.el)
}
}接着处理删除情况,如果旧节点开始下标小于旧节点技术下标,需要把多余的节点删除,因此增加判断
1
2
3
4
5else if(oldStartIdx <= oldEndIdx && newStartIdx > newEndIdx) {
for(let i = oldStartIdx; i <= oldEndIdx, i++) {
unmount(oldChildren[i])
}
}