VDOM diff
VDOM
- VDOM,JavaScript对象,即对真实DOM的描述;
- 虚拟DOM创建页面性能:创建JavaScript对象的计算量 + 创建真实DOM的计算量;(第一步,创建JavaScript对象,即真实DOM的描述;第二步,递归地遍历虚拟DOM树并创建真实DOM;)
- 虚拟DOM更新更新页面过程:1. 重新渲染JavaScript对象(虚拟DOM树);2. 比较新旧虚拟DOM Diff,找到变化的元素并更新它;
VDOM diff
- React diff 为了避免遍历节点的复杂度,只对比同一层的虚拟节点;
- newDOM中的节点存在,oldDOM中不存在,那么就新增一个节点;
- newDOM中的节点不存在,oldDOM中存在,那么就删除oldDOM中的节点;
- newDOM和oldDOM中的节点都存在,对比是否是同一个节点,是同一个节点再比较子元素是否相同;
- 两个节点都存在时,比较它们的子节点,若子节点是文本节点,更新子节点的文本为new节点的文本,如果子节点不是文本节点且不相同时,比如子节点顺序发生改变,React中使用的是下标递增的方式来判断节点的位置是否需要调整的,然后我们开始遍历newDOM,依次查询newDOM中的节点在oldDOM中的下标位置,并记录下来,如果新的下标小于之前保存的下标说明位置需要调整,调整到newDOM的前一个真实节点之后,如果不小于,则保持位置不用调整;
- vue2 diff
- Vue将虚拟DOM和watcher相结合,每个组件都有自己对应的虚拟DOM,那么当组件内部的数据发生改变时,Vue是怎么样同步渲染页面的呢?
- 当组件内部数据发生改变时,会触发数据的setter方法,进而通知到watcher对象,watcher会触发更新函数,通过render函数获取到新的虚拟DOM结构,然后将newDOM和oldDOM进行解析获取到最小变动,根据最小变动内容更新页面DOM。
- newDOM中的节点存在,oldDOM中不存在,那么就新增一个节点;
- newDOM中的节点不存在,oldDOM中存在,那么就删除oldDOM中的节点;
- 新老节点相同时,并且子节点不同的情况,Vue中是如何处理的:
- 首尾比对的diff算法;
- 1--newDOM和oldDOM首位对比,相同,对比位置同时向后移动,节点位置不需要调整;
- 2--newDOM和oldDOM末位对比,相同,对比位置同时向前移动,节点位置不需要调整;
- 3--newDOM末位和oldDOM首位对比,相同,newDOM向前移动,oldDOM向后移动将当前节点移动到oldDOM未比对节点的最后一个节点的后面;
- 4--newDOM首位和oldDOM末位对比,相同,newDOM向后移动,oldDOM向前移动,将当前节点移动到oldDOM未,比对节点的第一个节点的前面;
- 若以上四个步骤比对完,并没有相同的节点,则需要将newDOM中的第一个节点,去oldDOM中遍历查询,查找到后,进行移动,并将newStart指针往后移一位;
- 依次重复上面的过程,直到遍历结束;newDOM中的newStart > newEnd时,说明已经遍历完成了,此时oldDOM中剩余的节点即为待删除节点,在父节点中依次删除就可以了
- vue3 diff
- 在Vue2的四种对比基础上,Vue3只保留了首首对比和尾尾对比,将首首对比和尾尾对比的结果排除后,获取剩下的newDOM节点的最大递增子序列,然后将不在递增子序列中的节点根据子序列的位置进行插入。
- 存在最大序列中的节点保持不变,不存在的根据最大序列的值来判断插入位置,最终完成newDOM的节点更新;依次往前遍历;
参考&感谢各路大神
Vue3
[vue.js设计与实现-霍春阳]
宝剑锋从磨砺出,梅花香自苦寒来。