vue页面更新patch的实现示例

2020-06-16 06:45:25易采站长站整理

patchVode

将相同的旧节点DOM添加到旧起始节点DOM前面
将相同的旧节点置为undefined
oldCh[idxInOld] = undefined

newStartVnode = newCh[++newStartIdx]

b)key相同,但标签类型不同的节点

创建新节点DOM并添加到旧起始节点DOM的前面

newStartVnode = newCh[++newStartIdx]

循环结束

a)如果旧节点遍历完(

oldStartIdx > oldEndIdx

把剩余未处理新节点DOM添加到上一个新结尾节点DOM前面(从新起始节点到新结尾节点,都未处理过)

b)如果新节点遍历完(

newStartIdx > newEndIdx

移除旧起始和结尾节点以及他们之间的节点的DOM(从旧起始节点到旧结尾节点,可能存在处理过的节点,但处理过已被置为undefined)


function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
var oldStartIdx = 0;// 表示当前正在处理的旧起始节点序号
var newStartIdx = 0;// 表示当前正在处理的新起始节点序号
var oldEndIdx = oldCh.length - 1;// 表示当前正在处理的旧结尾节点序号
var oldStartVnode = oldCh[0];// 表示当前正在处理的旧起始节点
var oldEndVnode = oldCh[oldEndIdx];// 表示当前正在处理的旧结尾节点
var newEndIdx = newCh.length - 1;// 表示当前正在处理的新结尾节点序号
var newStartVnode = newCh[0];// 表示当前正在处理的新起始节点
var newEndVnode = newCh[newEndIdx];// 表示当前正在处理的新结尾节点
var oldKeyToIdx, idxInOld, vnodeToMove, refElm;
...
while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
if (isUndef(oldStartVnode)) {
oldStartVnode = oldCh[++oldStartIdx]; // Vnode has been moved left
} else if (isUndef(oldEndVnode)) {
oldEndVnode = oldCh[--oldEndIdx];
} else if (sameVnode(oldStartVnode, newStartVnode)) {
patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);
oldStartVnode = oldCh[++oldStartIdx];
newStartVnode = newCh[++newStartIdx];
} else if (sameVnode(oldEndVnode, newEndVnode)) {
patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx);
oldEndVnode = oldCh[--oldEndIdx];
newEndVnode = newCh[--newEndIdx];
} else if (sameVnode(oldStartVnode, newEndVnode)) { // Vnode moved right
patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx);
canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm));
oldStartVnode = oldCh[++oldStartIdx];