上篇文章说到了patch
中的新增dom
过程,这篇会说diif
算法。Vue
的diff
算法是基于snabbdom
的,另外网上也有很多分析的文章,我自己是看的掘金上的篇博客。
在这里我主要会从代码实现上来描述。
入口
在patch
函数中,如果新旧 vnode 属于sameVnode
,那么就会执行patchVnode
过程:
1 | function patch(oldVnode, vnode, hydrating, removeOnly) { |
sameVnode
的判断逻辑如下:
1 | function sameVnode(a, b) { |
Vue
对于sameVnode
的判断逻辑和snabbdom
不同,这点可以了解下。真正的patch
逻辑在patchVnode
函数中。
patchVnode
1 | function patchVnode(oldVnode, vnode, insertedVnodeQueue, removeOnly) { |
isStatic
属性为true
的条件是当前节点是静态节点,所以这里vnode
和oldVnode
都是静态节点。
(isTrue(vnode.isCloned) || isTrue(vnode.isOnce))
我们在生成render
函数字符串中,会有_m
或_o
,他们分别是renderStatic
和markOnce
方法(src/core/instance/render-static.js中)
。我们的patchVnode
是在数据变化后调用,render
方法是不变的,只不过因为执行render
函数时数据变了,所以生成的vnode
对象和之前不同。以_m
为例,再次执行_m
函数,会直接从vm._staticTrees
中获取tree
,并通过cloneVNode
方法克隆一份出来,这种情况下vnode.isCloned
值为true
。
addVnodes
和removeVnodes
用于批量新增、删除dom
,这里不再展开。
剩下的主要逻辑是在updateChildren
中,它是用于比较两个数组。
updateChildren
1 | function updateChildren(parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) { |
这就是diff
算法的核心了,已经加上了非常详细的注释。大家可以先参考其他的文章了解diff
,然后再来这里看代码的实现会轻松很多。