什么是虚拟DOM
为什么要使用虚拟DOM:
h函数
Vnode的创建过程
VNode 的处理过程
文章比较长,首先先看一下vnode的创建和处理过程的简要(源码下面都有注释,需要可以细看):
什么是虚拟DOM
虚拟DOM(Virtual DOM)是使用JavaScript对象描述真实DOM
Vue.js中的虚拟DOM借鉴Snabbdom,并添加了Vue.js的特征,例如:指令和组件机制
为什么要使用虚拟DOM:
避免直接操作真实DOM,提高开发效率
作为一个中间层可以跨平台,支持web端渲染,还可以支持服务端渲染
虚拟DOM不一定可以提高性能:
首次渲染的时候会增加开销
复杂视图情况下提升渲染性能
h函数
vm.$createElement(tag, data, children, normalizeChildren)
tag:标签名或者组件对象
data:描述tag,可以设置DOM的属性或者标签的属性
children:tag中的文本内容或者子节点
render(h){
// h(tag, data, children)
// return h('h1', this.msg)
// return h('h1', {domProps: {innerHTML: this.msg}})
// return h('h1', {attrs: {id: 'title'}}, this.msg)
// children 当前h1对应的子节点
// data 创建函数时传递的data选项
// elm 真实dom
// tag 调用h函数时传递的第一个属性
const vnode = h(
'h1',
{
attrs: {
id:'title' //设置属性id 可以在css 里面设置样式
}
},
this.msg
)
console.log(vnode);
return vnode;
}
vNode核心属性:tag, data,children,text,elm,key
VNode就是用JS对象描述一个真实的DOM
为什么使用VNode:真实DOM有很多无用的属性,且操作DOM对性能消耗比较大;
VNode的作用:渲染前将templatem模版编译成VNode缓存,然后数据更新后对比新旧vnode,根据有变化的vnode创建出真实的节点插入到视图中完成一次视图更新。
源码中通过VNode类实例化不同的虚拟节点;
VNode节点类型分为注释节点,文本节点,元素节点,组件节点,函数式节点,克隆节点;
创建不同类型的节点调用不同的方法如createEmptyVNode,createTetVNode等,不同节点生成的属性不同。
DOM-Diff
对比vnode的算法叫做DOM-Diff算法,这个过程叫做patch过程,其中对比新旧vnode以新的为基准,操作旧的vnode;
对比新旧节点后的操作分为创建、删除、更新。
创建
删除
获取父节点,parent.removeChildren();
更新
更新需要判断新旧节点的类型,看图。难点是新旧节点都有子节点的情况,需要循环对比。
更新子节点
比较复杂的情况便是新旧vnode都是有子节点的节点,那么对比后的执行创建子节点、删除~、移动~、更新~的操作。外层循环newVnode内层循环oldVnode,对比新的操作旧的。
注意的是新增和移动为了避免在与其它操作的节点冲突,目标位置应该选择未处理的节点之前而不是已处理之后。
优化策略
进行四步对比,详见链接,思路是四个游标,从两边向中间循环,如果新前和新后相遇了 那么旧前和旧后之间的节点旧删掉,如果旧前旧后相遇了,那么新前新后中间的便是新节点,截取后插入。四步对比没有相同的便双重循环新旧vnode;