简单来讲,vue的虚拟dom就是一个JavaScript对象,用对象的方式去描述dom的结构。
<div class="a" id="b">我是内容</div>
{
tag:'div', // 元素标签
attrs:{ // 属性
class:'a',
id:'b'
},
text:'我是内容', // 文本内容
children:[] // 子元素
}
为什么要使用虚拟dom
我们知道浏览器将页面的dom设计的非常复杂,而vue的特点之一是数据驱动视图,换言之,也就是说,vue是通过数据的变化来驱动视图的更新,也就意味着是数据变化对dom的操作非常的频繁,这样的代价是非常大,但是我们又逃不多对dom的操作,那么怎么办呢?其实很简单,我们可以在数据变化前后生成2份dom,然后通过diff算法将这2份dom做比较,看看他们有什么不一样的,将不一样的dom更新到真实的dom上,是不是就大大就减少了真实的dom的操作,其实就是我们所说的虚拟dom。
vue如何实现虚拟dom
那么vue中是如何实现的虚拟dom呢?其实也很简单,就是通过vnode这样一个类实现,直接上源码:
// 源码位置:src/core/vdom/vnode.js
export default class VNode {
constructor (
tag?: string,
data?: VNodeData,
children?: ?Array<VNode>,
text?: string,
elm?: Node,
context?: Component,
componentOptions?: VNodeComponentOptions,
asyncFactory?: Function
) {
this.tag = tag /*当前节点的标签名*/
this.data = data /*当前节点对应的对象,包含了具体的一些数据信息,是一个VNodeData类型,可以参考VNodeData类型中的数据信息*/
this.children = children /*当前节点的子节点,是一个数组*/
this.text = text /*当前节点的文本*/
this.elm = elm /*当前虚拟节点对应的真实dom节点*/
this.ns = undefined /*当前节点的名字空间*/
this.context = context /*当前组件节点对应的Vue实例*/
this.fnContext = undefined /*函数式组件对应的Vue实例*/
this.fnOptions = undefined
this.fnScopeId = undefined
this.key = data && data.key /*节点的key属性,被当作节点的标志,用以优化*/
this.componentOptions = componentOptions /*组件的option选项*/
this.componentInstance = undefined /*当前节点对应的组件的实例*/
this.parent = undefined /*当前节点的父节点*/
this.raw = false /*简而言之就是是否为原生HTML或只是普通文本,innerHTML的时候为true,textContent的时候为false*/
this.isStatic = false /*静态节点标志*/
this.isRootInsert = true /*是否作为跟节点插入*/
this.isComment = false /*是否为注释节点*/
this.isCloned = false /*是否为克隆节点*/
this.isOnce = false /*是否有v-once指令*/
this.asyncFactory = asyncFactory
this.asyncMeta = undefined
this.isAsyncPlaceholder = false
}
get child (): Component | void {
return this.componentInstance
}
}
这样一来,这个VNode类就实现了所有的真实dom属性。
VNode类型
- 注释节点
- 文本节点
- 元素节点
- 组件节点
- 函数式组件节点
- 克隆节点
Diff算法
提到dom,diff算法就是被紧紧的联系在一起,那么到底什么是diff算法呢?
在vue中把diff算法称之为patch的过程,patch的意思就是打补丁。
那么这个patch的过程是怎么样的呢?
我们知道:对于dom的操作无非就是增、删、改、查这四个字,那么vue的patch的过程其实就是VNode的增、删、改的过程。
所以首先要讲清楚patch的对象是什么?那就是,
对操作前后的dom树同一层的节点进行对比,一层一层对比
使用key来给每个节点做唯一标识,diff算法就可以正确地识别此节点,找到正确地位置插入新的节点。
借鉴引用了大神的文章:blog.csdn.net/leelxp/arti…