vue-vdom-diff
分为以下几个流程:
newVNode === undefined && oldVNode !== undefined直接做移除操作。oldVNode === undefined做新增操作。isSomeVNode(oldVNode,newVNode) === true进入children的patch流程。- 进入更新当前
VNode流程。
vnode updateChildren 流程
vnode children的更新流程跟数组操作类似。
-
oldVnode = [a, b, c, d]; newVnode = [c, d]; -
oldVnode = [a, b, c, d]; newVnode = [e, f, a, b, c, d]; -
oldVnode = [a, b, c, d]; newVnode = [a, b]; -
oldVnode = [a, b, c, d]; newVnode = [a, b, c, d, e, f]; -
oldVnode = [a, b, c, d]; newVnode = [a, b, e, f, c, d]; -
oldVnode = [a, b, c, d]; newVnode = [a, d];
以上是分成的原子操作,但是实际生产中可能发生的情况更加复杂,是上面的任意组合。
patchChildren 比较流程
循环判断条件:oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx,即还没有遍历完oldCh 或者 newCh,只要有一个遍历完了,就会跳出循环。
-
首先判断旧的开始节点
oldStartVnode是否为空1.1 为空的话,将
oldStartIdx向后偏移一位,并重新对oldStartVnode = oldCh[++oldStartIdx]进行赋值,满足循环的情况下重新进入步骤1。 -
判断旧的结束节点
oldEndVnode是否为空2.1 为空的话,将
oldEndIdx向前偏移一位,并重新对oldEndVnode = oldCh[--oldEndIdx]进行赋值,满足循环的情况下重新进入步骤1。 -
对比新旧的开始节点
sameVnode(oldStartVnode, newStartVnode)是否是同一个VNode3.1 是同一个
VNode,进入他们的children patch流程。3.2 将
oldStartIdx、newStartIdx继续向后偏移一位,并对oldStartVnode、newStartVnode进行重新赋值,满足循环的情况下重新进入步骤1。 -
对比新旧的结束节点
sameVnode(oldEndVnode, newEndVnode)是否是同一个VNode4.1 是同一个
VNode,进入他们的children patch流程。4.2 将
oldEndIdx、newEndIdx继续向后偏移一位,并对oldEndVnode、newEndVnode进行重新赋值,满足循环的情况下重新进入步骤1。 -
对比旧的开始节点、新的结束节点
sameVnode(oldStartVnode, newEndVnode)是否是同一个VNode5.1 是同一个
VNode,进入他们的children patch流程。5.2 如果不是在
<transition-group>组件内用的话,将oldStartVnode.elm移动oldEndVnode.elm.nextSibling的位置。5.3
oldStartIdx向后偏移一位,newEndIdx向前偏移一位。5.4 并对
oldStartVnode、newEndVnode进行重新赋值,满足循环的情况下重新进入步骤1。 -
对比旧的结束节点、新的开始节点
sameVnode(oldEndVnode, newStartVnode)是否是同一个VNode6.1 是同一个
VNode,进入他们的children patch流程。6.2 如果不是在
<transition-group>组件内用的话,将oldEndVnode.elm移动oldStartVnode.elm.nextSibling的位置。6.3
oldEndIdx向前偏移一位,newStartIdx向后偏移一位。6.4 并对
oldEndVnode、newStartVnode进行重新赋值,满足循环的情况下重新进入步骤1。 -
建立
oldKeyToIdx这个map,数据结构如下:interface OldKeyToIdxMap { [key: string]: number; }7.1 根据
newStartVnode.key去oldKeyToIdx找对于旧的VNode的idxInOld。7.1.1 未找到,根据
newStartVnode重新创建元素。7.1.2 取出并赋值
vnodeToMove = oldCh[idxInOld]。7.1.2.1 判断
sameVnode(vnodeToMove, newStartVnode)。7.1.2.1.1 为
true,进入他们的children patch流程。7.1.2.1.2 将旧的赋值成
oldCh[idxInOld] = undefined7.1.2.1.2 并移动
nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm)7.1.3
newStartIdx向后偏移一位,满足循环的情况下重新进入步骤1。
不满足循环条件。
oldStartIdx > oldEndIdx,进入创建新增的VNode流程。newStartIdx > newEndIdx,进入移除oldCh里面的VNode流程。