从源码角度解析Vue重排与重绘
众所周知,Vue通过数据绑定来修改视图,当某个数据被修改的时候,set
方法会让闭包中的Dep
调用notify
通知所有订阅者Watcher
,Watcher
通过get
方法执行vm._update(...)
,进而去更新视图。
在vm._update(...)
中,Vue会调用patch(...)
(vdom/patch.js第659行左右),将新产生的vnode
与数据未变更之前的旧的prevVnode
进行对比。
在patch(...)
方法中,Vue通过sameVnode(...)
(vdom/patch.js第42行左右)对新旧两个Vnode对象进行比较,通过比对它们的标签名(tag
)、键值(key
)、是否都拥有data选项(isDef(data)
)以及是否都为注释节点(isComment
)来确定这两个Vnode映射的真实DOM节点为同一个。只有确定它们是同一个真实DOM节点的不同映射时,才会执行下一步patchVnode(...)
(vdom/patch.js第501行左右)。
在patchVnode(...)
中,Vue会依据新旧两个Vnode对象是否拥有子节点children
执行不同的DOM操作,当两个Vnode对象都有子节点时,会调用updateChildren(...)
(vdom/patch.js第501行左右)方法递归的对子节点进行patchVnode(...)
。
Vue中的diff算法
请注意,diff算法是一个使用了递归思想的算法,但是它的时间复杂度只有O(n),这是因为,每一个旧的Vnode只跟与它同层的映射为同一个真实DOM节点的新Vnode进行比较。
这里有一篇很好的专门讲解diff算法的文章链接