1、同层对比
diff算法只会同层对比,是深度优先
2、对比流程
- 数据改变触发setter,通知所有订阅者,订阅者门通过调用patch更新补丁
- patch
- 对比是否标签相同,托相同patchVnode对比下一层
- patchVnode(判断子节点一方有一方无)
- 判断
newVnode
和oldVnode
是否指向同一个对象,如果是,那么直接return
- 如果他们都有文本节点并且不相等,那么将
el
的文本节点设置为newVnode
的文本节点。 - 如果
oldVnode
有子节点而newVnode
没有,则删除el
的子节点 - 如果
oldVnode
没有子节点而newVnode
有,则将newVnode
的子节点真实化之后添加到el
- 判断
- updateChildren(两方都有子节点,用首尾指针)
- 1、
oldS 和 newS
使用sameVnode方法
进行比较,sameVnode(oldS, newS)
- 2、
oldS 和 newE
使用sameVnode方法
进行比较,sameVnode(oldS, newE)
- 3、
oldE 和 newS
使用sameVnode方法
进行比较,sameVnode(oldE, newS)
- 4、
oldE 和 newE
使用sameVnode方法
进行比较,sameVnode(oldE, newE)
- 5、如果以上逻辑都匹配不到,再把所有旧子节点的
key
做一个映射到旧节点下标的key -> index
表,然后用新vnode
的key
去找出在旧节点中可以复用的位置。
接下来就以上面代码为例,分析一下比较的过程
分析之前,请大家记住一点,最终的渲染结果都要以newVDOM为准,这也解释了为什么之后的节点移动需要移动到newVDOM所对应的位置
- 第一步
oldS = a, oldE = c
newS = b, newE = a
比较结果:oldS 和 newE
相等,需要把节点a
移动到newE
所对应的位置,也就是末尾,同时oldS++
,newE--
- 第二步
oldS = b, oldE = c
newS = b, newE = e
比较结果:oldS 和 newS
相等,需要把节点b
移动到newS
所对应的位置,同时oldS++
,newS++
- 第三步
oldS = c, oldE = c
newS = c, newE = e
比较结果:oldS、oldE 和 newS
相等,需要把节点c
移动到newS
所对应的位置,同时oldS++
,newS++
- 第四步
oldS > oldE
,则oldCh
先遍历完成了,而newCh
还没遍历完,说明newCh比oldCh多
,所以需要将多出来的节点,插入到真实DOM上对应的位置上
React的diff与vue的diff
reactdiff:是单端,ABCD-》DABC
遍历新节点:D
查找老节点是否复用:A。B。C。D找到D
新节点:A
找到老节点:A,移动到D后边