vue页面更新patch的实现示例

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

a)如果新旧节点完全相同(引用相同 oldVnode === vnode)

直接返回不处理

b) 如果新节点不是文本节点

a)都存在子节点,新旧节点的子节点数组引用不同(oldCh !== ch)

updateChildren

b)新节点有子节点,旧节点没有

1)查重子节点(key)
2)如果旧节点是文本节点,先清空文本
3)创建子节点DOM元素

c)旧节点有子节点,新节点没有

移除子节点以及DOM

d)旧节点是文本节点

清除文本

c)如果新节点是文本节点,并且和旧节点文本不相同

则直接替换文本内容。

d)其他(新节点是文本节点,并且和旧节点相同)

不处理


function patchVnode (
oldVnode,
vnode,
insertedVnodeQueue,
ownerArray,
index,
removeOnly
) {
if (oldVnode === vnode) {
return
}
...
if (isUndef(vnode.text)) {
if (isDef(oldCh) && isDef(ch)) {
if (oldCh !== ch) { updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly); }
} else if (isDef(ch)) {
if (process.env.NODE_ENV !== 'production') {
checkDuplicateKeys(ch);
}
if (isDef(oldVnode.text)) { nodeOps.setTextContent(elm, ''); }
addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue);
} else if (isDef(oldCh)) {
removeVnodes(elm, oldCh, 0, oldCh.length - 1);
} else if (isDef(oldVnode.text)) {
nodeOps.setTextContent(elm, '');
}
} else if (oldVnode.text !== vnode.text) {
nodeOps.setTextContent(elm, vnode.text);
}
...
}

updateChildren方法

updateChildren方法处理相同新旧节点的子节点。方法定义了以下变量(updateChildren的节点都表示的是子节点):


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, // 尚未处理的旧节点key值映射
idxInOld, // 与新节点key值相同的旧节点序号
vnodeToMove, // 与新节点key值相同的旧节点
refElm;// 指向当前正在处理的新结尾节点的后一个节点(已处理)的DOM元素