Vue diff原理
灵感来源
Vitrual DOM与真实DOM
真实DOM
Virtual DOM(伪代码)
详解
仅在同层比较,不会跨层级比较

流程图

代码部分
patch
patch函数主要进行了两个分支流程
判断两节点是否是一样的,如果是则执行
patchVnode不一样则用
Vnode替换oldVnode
patchVnode
关键流程
找到对应的真实 dom,称为
el判断
Vnode和oldVnode是否指向同一个对象,如果是,那么直接return如果他们都有文本节点并且不相等,那么将
el的文本节点设置为Vnode的文本节点如果
oldVnode有子节点而Vnode没有,则删除el的子节点如果
oldVnode没有子节点而Vnode有,则将Vnode的子节点真实化之后添加到el如果两者都有子节点,则执行
updateChildren函数比较子节点,这一步很重要
updateChildern(核心)

我们将它们取出来并分别用 s 和 e 指针指向它们的头 child 和尾 child

现在分别对 oldS、oldE、S、E 两两做 sameVnode 比较,有四种比较方式,当其中两个能匹配上那么真实 dom 中的相应节点会移到 Vnode 相应的位置,这句话有点绕,打个比方
如果是
oldS和E匹配上了,那么真实dom中的第一个节点会移到最后如果是
oldE和S匹配上了,那么真实dom中的最后一个节点会移到最前,匹配上的两个指针向中间移动如果四种匹配没有一对是成功的,分为两种情况
如果新旧子节点都存在
key,那么会根据oldChild的key生成一张hash表,用S的key与hash表做匹配,匹配成功就判断S和匹配节点是否为sameNode,如果是,就在真实dom中将成功的节点移到最前面,否则,将S生成对应的节点插入到dom中对应的oldS位置,oldS和S指针向中间移动。如果没有
key,则直接将S生成新的节点插入真实DOM(ps:这下可以解释为什么v-for的时候需要设置key了,如果没有key那么就只会做四种匹配,就算指针中间有可复用的节点都不能被复用了)
再配个图(假设下图中的所有节点都是有 key 的,且 key 为自身的值)

1.第一步
oldS 和 S 匹配,则将 dom 中的 a 节点放到第一个,已经是第一个了就不管了,此时 dom 的位置为:a b d
2. 第二步
oldS 和 E 匹配,就将原本的 b 节点移动到最后,因为 E 是最后一个节点,他们位置要一致,这就是上面说的:当其中两个能匹配上那么真实 dom 中的相应节点会移到 Vnode 相应的位置,此时 dom 的位置为:a d b
3. 第三步
oldE 和 E 匹配,位置不变此时 dom 的位置为:a d b
4. 第四步
遍历结束,说明 oldCh 先遍历完。就将剩余的 vCh 节点根据自己的的 index 插入到真实 dom 中去,此时 dom 位置为:a c d b
这个匹配过程的结束有两个条件:
oldS > oldE表示oldCh先遍历完,那么就将多余的vCh根据index添加到dom中去(如上图)S > E表示vCh先遍历完,那么就在真实dom中将区间为[oldS, oldE]的多余节点删掉

最后更新于
这有帮助吗?