1. 前言
- vue 中的
虚拟 DOM
,diff算法
,大家都有所耳闻- 但是总感觉不那么透彻,所以看了几遍官网,简单整理如下
- 后续发现有文章总结,但是在github上面,有些人可能访问不到,所以我就简单写下
2. 虚拟 DOM 是什么 what
- 虚拟 DOM (Virtual DOM,简称 VDOM) 是一种编程概念,意为将目标所需的 UI 通过数据结构“虚拟”地表示出来,保存在内存中,然后将真实的 DOM 与之保持同步。
- 这个概念是由 React 率先开拓,随后在许多不同的框架中都有不同的实现,当然也包括 Vue
- 与其说虚拟 DOM 是一种具体的技术,不如说是一种模式,所以并没有一个标准的实现
3. diff 算法 是什么 what
- 如果我们有两份虚拟 DOM 树,渲染器将会有
比较
地遍历
它们,找出它们之间的区别
,并应用这其中的变化到真实的 DOM 上。这个过程被称为更新 (patch),又被称为“比对”(diffing) 或“协调”(reconciliation)。- 一个运行时渲染器将会遍历整个虚拟 DOM 树,并据此构建真实的 DOM 树。这个过程被称为挂载 (mount)。
- 也就是说
diff
算法是在 挂载 的时候,对虚拟 DOM /新旧 VNode 进行比对的算法- 再具体
diff 算法
是一种通过同层
的树节点进行比较
的高效算法
4. 特点
- 比较只会在同层级进行, 不会跨层级比较
- 在diff比较的过程中,循环从两边向中间比较
5. 比较方式
- diff整体策略为:深度优先,同层比较
image.png- 比较的过程中,循环从两边向中间收拢
image.png
6. 原理分析
- 当数据发生改变时,
set
方法会调用Dep.notify
通知所有订阅者Watcher
,订阅者
就会调用patch给真实的DOM打补丁,更新相应的视图- 源码位置:src/core/vdom/patch.js
- 主要是一个
function patch(oldVnode, vnode, hydrating, removeOnly) {}
函数function patchVnode (oldVnode, vnode, insertedVnodeQueue, removeOnly) {}
- 源码挺多的也有分析原址
7. 小结
- 当数据发生改变时,
订阅者
watcher就会调用patch
给真实的DOM打补丁
通过isSameVnode进行判断,相同则调用patchVnode方法- patchVnode做了以下操作:
2.1 找到对应的真实dom,称为el
2.2 如果都有都有文本节点且不相等,将el文本节点设置为Vnode的文本节点
2.3 如果oldVnode有子节点而VNode没有,则删除el子节点
2.4 如果oldVnode没有子节点而VNode有,则将VNode的子节点真实化后添加到el
如果两者都有子节点,则执行updateChildren函数比较子节点- updateChildren主要做了以下操作:
3.1 设置新旧VNode的头尾指针
3.2 新旧头尾指针进行比较,循环向中间靠拢,根据情况调用patchVnode进行patch重复流程、调用createElem创建一个新节点,从哈希表寻找 key一致的VNode 节点再分情况操作