VUE中的虚拟DOM
1. 首先先讲一下什么是虚拟DOM,我们把组成一个DOM节点的必要的东西通过一个JS对象表示出来,那么这个JS对象就可以用来描述这个DOM对象,我们把这个JS对象称为这个DOM对象的虚拟DOM节点.
2. 为什么要有虚拟DOM:直接操作真实DOM是非常消耗性能的,为了尽可能的在更新视图的时候减少DOM操作,我们可以通过JS的计算性能来判断数据变化前后的状态,只更新那些需要更新的部分。
3. VUE中的虚拟DOM是怎么实现的:
3.1.VNode类 :在VUE中存在一个VNode类,通过这个类,我们可以实例化出不同类型的虚拟DOM节点:
	// 源码位置: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
	  }
}
3.2:通过属性之间不同的搭配,VNode类可以描述出各种类型的真实DOM节点,再源码里:可以描述出以下几种类型的节点
○ 注释节点 ○ 文本节点 ○ 克隆节点 ○ 元素节点 ○ 组件节点 函数式组件节点
3.2.1:注释节点 :只需要两个属性,注释的文本text属性以及注释节点isComment属性
		// 创建注释节点
export const createEmptyVNode = (text: string = '') => {
  const node = new VNode()
  node.text = text
  node.isComment = true
  return node
}
3.2.2:文本节点 :只需要一个文本text属性
		// 创建文本节点
export function createTextVNode (val: string | number) {
  return new VNode(undefined, undefined, undefined, String(val))
}
3.2.3:克隆节点 :克隆节点就是把已有节点的属性全部复制到新节点中去,其中,克隆节点中的isCloud为true
		// 创建克隆节点
export function cloneVNode (vnode: VNode): VNode {
  const cloned = new VNode(
    vnode.tag,
    vnode.data,
    vnode.children,
    vnode.text,
    vnode.elm,
    vnode.context,
    vnode.componentOptions,
    vnode.asyncFactory
  )
  cloned.ns = vnode.ns
  cloned.isStatic = vnode.isStatic
  cloned.key = vnode.key
  cloned.isComment = vnode.isComment
  cloned.fnContext = vnode.fnContext
  cloned.fnOptions = vnode.fnOptions
  cloned.fnScopeId = vnode.fnScopeId
  cloned.asyncMeta = vnode.asyncMeta
  cloned.isCloned = true
  return cloned
}
3.2.4:元素节点 :元素节点更贴近于真实DOM节点,它有描述节点标签名词的tag属性,描述节点属性像class,attributes等的data属性,还有包含子节点信息的children属性等,由于所包含的情况相比很复杂,因此源码中也不能写死。下面举例子看一下
		// 真实DOM节点
<div id='a'><span>VUE源码</span></div>
		// VNode节点
{
  tag:'div',
  data:{},
  children:[
    {
      tag:'span',
      text:'VUE源码'
    }
  ]
}
