虚拟DOM(vnode)
虚拟dom就是用js对象来描述真实的dom节点。 diff算法去比较新旧vnode的差异,将变化的地方更新到真实的dom上。
- diff是什么时刻触发的? 数据发生变化的时候,会触发setter通知,通知的方式是把watcher添加到异步更新队列,在每次事件循环队列结束时,清空事件队列,在这个过程中所有的watcher都会执行他们的更新函数,更新函数在执行的时候其实调用了我们的组件渲染函数和组件更新函数,这时会重新渲染最新的虚拟dom,然后执行更新函数,比较新旧虚拟dom。
- dom-diff其实就是创建、删除、更新节点
-
vnode创建 有注释节点、文本节点、元素节点能被创建、插入到dom节点中 判断vnode是否有tag标签,如果有,创建标签节点;如果没有,判断vnode是否有iscommend属性,如果有,创建注释node;如果没有则创建文本node
-
vnode删除 如果新的vnode中没有而旧的vnode中有,则在旧的vnode中删除即可。
-
vnode更新 更新节点有三种情况
-
vnode为静态节点:无需比较直接跳过
-
vnode为文本节点 如果vnode为文本节点,此时如果旧节点也是文本节点,只需比较文本的差异进行更新。如果旧节点不是文本节点,则直接替换成vnode
-
vnode为元素节点 (1)vnode含有子节点 a. 如果新的vnode中包含子节点,先检查旧的vnode中是否包含子节点,如果包含,则递归更新旧节点。如果旧节点不包含子节点,则直接创建一分新节点中的子节点插入到旧节点。如果旧节点中是文本节点,则把文本节点清空再把创建的子节点插入到旧节点。 (2)vnode不含子节点 b. 如果新的vnode中没有子节点,此时如果旧vnode中含有子节点,直接清空子节点。
-
vue3相对于vue2diff算法的优化点:
- 事件缓存
- 添加静态标记,vue2是全量diff,vue3是静态标记+部分diff
- 静态提升。后续直接复用静态节点
- vue2在updateChildren中对比变更,vue3是在patchKeyedChildren函数中,基于最长递增子序列去移动/添加/删除节点。