Vue源码之patch顺口溜了解一下

2,038 阅读3分钟

通过同层的树节点进行比较而非对树进行逐层搜索遍历的方式,所以时间复杂度只有O(n),是一种相当高效的算法


同层级只做三件事:增删改。

具体规则是:

  • new VNode不存在就删;
  • old VNode不存在就增;
  • 都存在就 比较类型,类型不同直接替换、类型相同执行更新 

两个VNode类型相同,就执行更新操作,包括三种类型操作:属性更新PROPS、文本更新TEXT、子节点更新REORDER

  1. 如果新旧VNode都是静态的,那么只需要替换elm以及componentInstance即可。

  2. 新老节点均有children子节点,则对子节点进行diff操作,调用updateChildren

  3. 如果老节点没有子节点而新节点存在子节点,先清空老节点DOM的文本内容,然后为当前DOM节

    点加入子节点。

  4. 当新节点没有子节点而老节点有子节点的时候,则移除该DOM节点的所有子节点。

  5. 当新老节点都无子节点的时候,只是文本的替换。 

⚠️  下面诠释顺口溜打开:src/core/vdom/patch.js文件

一、开始游标<=结束游标

首先oldStartVnode、oldEndVnodenewStartVnode、newEndVnode两两交叉比较(1-4) 

1. 旧头对新头,排着队伍完后走

oldStartVnodenewStartVnode  满足sameVnode,直接将该 VNode节点进行patchVnode即可,不需再遍历就完成了一次循环 




2. 旧尾对新尾,拉着尾巴顺着走

当 oldEndVnodenewEndVnode满足sameVnode,直接将该 VNode节点进行patchVnode即可,不需再遍历就完成了一次循环 




3. 旧头对新尾,按着新尾排排队

如果oldStartVnodenewEndVnode满足sameVnode。说明oldStartVnode已经跑到了oldEndVnode 后面去了,进行patchVnode的同时还需要将真实DOM节点移动到oldEndVnode的后面。 




4. 旧尾对新头,揪着旧尾前面走

如果oldEndVnodenewStartVnode满足sameVnode,说明oldEndVnode跑到了oldStartVnode的前面,进行patchVnode的同时要将oldEndVnode对应DOM移动到oldStartVnode对应DOM的前面。 



5. 综上皆无果,老实循环接个来

如果以上情况均不符合,则在old VNode中找与newStartVnode满足sameVnodevnodeToMove,若 存在执行patchVnode,同时将vnodeToMove对应DOM移动到oldStartVnode对应的DOM的前面。 


当然也有可能newStartVnode在old VNode节点中找不到一致的key,或者是即便key相同却不是 sameVnode,这个时候会调用createElm创建一个新的DOM节点放到old VNode最前面。 



二、老游标先结束oldStartIdx > oldEndIdx批量添加

当结束时oldStartIdx > oldEndIdx,这个时候旧的VNode节点已经遍历完了,但是新的节点还没有。说 明了新的VNode节点实际上比老的VNode节点多,需要将剩下的VNode对应的DOM插入到真实DOM 中,此时调用addVnodes(批量调用createElm接口)。 



三、新游标先结束newStartIdx > newEndIdx批量删除

当结束时newStartIdx > newEndIdx时,说明新的VNode节点已经遍历完了,但是老的节点还有 剩余,需要从文档中删 的节点删除。 





四、连贯起来