虚拟DOM
为什么引入虚拟DOM?
在响应式系统上就说到,页面的渲染是通过我们输入状态,然后生成DOM输出到页面上显示出来的,但是程序在运行时,状态是不停在变化的,每当状态发生了变化,就需要重新渲染。最简单粗暴的就是删除所有DOM,重新生成一份,但是这样操作DOM会造成相当大的性能浪费,并且通常只需要重新渲染有限个节点,因此各个框架有不同的解决方案,Angular是脏检查,React是使用虚拟DOM,Vue.js1.0使用细粒度的绑定,Vue.js2.0使用虚拟DOM。
什么是虚拟DOM?
虚拟DOM是通过状态生成一个虚拟节点树,然后使用虚拟节点树和上一次渲染视图使用的旧虚拟节点树进行对比,只渲染不同的部分。
使用模板来描述状态和DOM之间的映射关系
Vue 会通过模板编译,将模板转换成渲染函数,通过执行这个函数就能够得到一个虚拟节点树。 每次属性发生变化,会调用组件渲染函数生成新的虚拟节点树,然后将新生成的虚拟节点树与上一次渲染视图使用的旧虚拟节点树进行对比(diff),再把要更新的地方进行 DOM 操作(patch)。最后缓存这一次渲染视图使用的虚拟节点树的 VNode
VNode
VNode是什么?
VNode 其实就是虚拟节点,在 Vue.js 中存在一个 VNode 类,可以用来实例化不同类型的 vnode 实例来表示不同类型的 DOM 节点。
export default class VNode{
constructor(tag,data,children,text...){
this.tag=tag;
this.data=data;
.....
}
}
渲染视图的过程先创建vnode,然后再使用vnode去生成真实的DOM元素,最后插入到页面渲染视图。
VNode 的类型有以下几种:
注释节点
文本节点
元素节点
组件节点
函数式组件
克隆节点
辨别节点类型可以通过节点的属性,比如注释节点只有text和isComment两个有效属性,其余属性全都是默认undefined或者false
patch
patch 算法又叫 patching 算法,它主要是通过对比新旧 vnode 找到需要更新的节点进行更新。
patch的过程其实就是创建节点、删除节点和修改节点的过程。
创建节点什么时候发生?
- oldVnode不存在而Vnode存在时
- 首次渲染时
- vnode和oldVnode完全不是一个节点时
删除节点什么时候发生?
- 一个节点只在oldVnode时
- oldVnode和vnode完全不是一个节点时
更新节点发生在oldVnode和vnode是同一个节点
patch的主要是两个算法:patchVnode 和 updateChildren
patchVnode
updateChildren
更新子节点,也是 diff 的核心。
主要是 4 种操作:更新节点、新增节点、删除节点、移动节点。
注意是在循环中进行比对
新增子节点
当没有在 oldChildren 中找到本次循环所指向的新子节点的节点,就新建一个节点插入到所有未处理节点的前面
更新子节点。
同一个节点且同一位置
移动子节点。
同一个节点,但是位置不同,则把需要移动的节点移动到所有未处理节点的前面。
删除子节点。
本质上是删除哪些 oldChildren 存在但 newChildren 不存在的节点。
补充一个流程图。。。