登录
转载

VUE中的虚拟DOM

发布于 2021-04-07 阅读 41
  • 前端
  • JavaScript
  • HTML
转载

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源码'
    }
  ]
}


从这个例子看出,真实DOM节点中,DIV标签里包含了一个span标签,span标签里包含有一段文字,反映到VNode节点上就如上所示,tag表示标签名字,data表示标签的属性id等,children表示子节点数组.

3.2.5:组件节点 :除了有元素节点具有的属性之外,它还具有两个特有的特性,componentOptions:组件的option选项,例如组件中的props等,componentInstance:表示当前组件节点对应的VUE实例.

3.2.6:函数式组件节点 :相比较于组件节点,它又具有两个特有的特性,fnContext:函数式组件对应的VUE实例.fnOptions:函数式组件的option选项.

3.3:VNode的作用: 说了那么多,那么VNode在虚拟DOM的过程中到底起了什么作用呢?总的来说,VNode就是我们在视图渲染之前,把写好的template模板编译成VNode并且缓存起来,等待数据发生变化页面需要重新渲染的时候,我们把数据变化后生成的VNode与前一次缓存下来的VNode进行对比,找出差异,然后有差异的VNode对应的真是DOM节点就是需要重新渲染的节点,最后再根据有差异的VNode创建出真实的DOM节点再插入到视图中去,最终完成一次视图的更新.

评论区

零00
1粉丝

时光荏苒,我自清欢

0

0

0

举报