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]
的多余节点删掉
最后更新于