【一起读】深入浅出Vue.js——虚拟DOM之VNode

前文提到,vue使用虚拟DOM中主要做了两件事,一个是创建了VNode来模拟DOM树,另一个是通过patch算法比对新旧DOM的变更状态。本节主要介绍VNode相关,包括VNode是什么?VNode有什么作用?

6.1 VNode是什么

VNode是一个类,使用他可以实例化各种类型的vnode实例,不同的DOM元素对应不同类型的vnode。

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类型)
        this.children = children // 当前节点子节点
        this.text = text // 当前节点文本
        this.elm = elm // 当前节点对应的真实DOM节点
        this.ns = undefined // 当前节点命名空间
        this.context = context // 当前节点上下文
        this.fnContext = undefined // 函数化组件上下文
        this.fnOptions = undefined // 函数化组件配置项
        this.fnScopeId = undefined // 函数化组件ScopeId
        this.key = data && data.key // 子节点key属性
        this.componentOptions = componentOptions // 组件配置项 
        this.componentInstance = undefined // 组件实例
        this.parent = undefined // 当前节点父节点
        this.raw = false // 是否为原生HTML或只是普通文本
        this.isStatic = false // 静态节点标志 keep-alive
        this.isRootInsert = true // 是否作为根节点插入
        this.isComment = false // 是否为注释节点
        this.isCloned = false // 是否为克隆节点
        this.isOnce = false // 是否为v-once节点
        this.asyncFactory = asyncFactory // 异步工厂方法 
        this.asyncMeta = undefined // 异步Meta
        this.isAsyncPlaceholder = false // 是否为异步占位
    }

    // 容器实例向后兼容的别名
    get child (): Component | void {
        return this.componentInstance
    }
}

不同类型的vnode有不同的属性,更具体的说法是:不同类型的vnode有不同的有效属性。当使用VNode实例化一个vnode时,通过参数为实例设置属性时,无效的属性会默认被赋值为undefined或false。

根据DOM元素种类的不同,一共有六种vnode类型,分别是:注释节点、文本节点、元素节点、组件节点、函数式组件、克隆节点。

6.1.1 注释节点

创建一个注释节点:

export const createEmptyVNode = (val) => {
  const node = new VNode()
  node.text = 'val'
  node.isComment = true
  return node
}

一个注释节点只有两个有效属性,text和isComment,其余属性是默认值undefined和false。
举例一行注释代码:

 

这行代码对应的vnode为:

{
  text: "我是注释",
  isComment: true
}
6.1.2 文本节点

创建一个文本节点:

export const createTextVNode = (val) => {
   return new VNode(undefined, undefined, undefined, String(val))
}

文本节点只有一个有效属性就是 text:

{
  text: '我是文本',
}
6.1.3 克隆节点

克隆节点即字面意思,将一个节点克隆到一个新节点上面,好处是可以优化静态节点和插槽节点。静态节点除了首次渲染需要执行渲染函数获取vnode之外,后续更新不需要执行渲染函数重新生成vnode,这时可以使用克隆节点方法将vnode克隆一遍,然后使用克隆节点进行渲染,这样就不需要重新执行渲染函数生成静态节点的vnode,从而提升一定的性能。
创建一个克隆节点:

export function cloneVNode(vnode,deep){
    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.isCloned=vnode.isCloned
    if(deep&&vnode.children){
        cloned.children=cloneVNode(vnode.children)
    }
    return cloned;
}

克隆节点与被克隆节点的区别是isCloned属性。

6.1.4 元素节点
哈哈哈

上述代码对应的vnode为:

{
    tag: 'div',
    data: {
        class: 'demo',
    },
    children: [
        {
            tag: 'span',
            data: {
                class:'test'
                 },
            text: '哈哈哈'
        }
]
}

元素节点有四个有效属性:

  • tag:节点的名称,如p div span 等
  • data:元素的属性 如class attrs style等
  • children:当前节点的子节点列表
  • context:当前组件的Vue.js实例
6.1.5 组件节点

组件节点与元素节点类似,多了两个个独有属性:

  • componentOptions:组件节点的选项参数,包括propsData,tag,children等
  • componentInstance:组件的实例,即Vue.js的实例
6.1.6 函数式组件

函数式组件与组件节点类似,额外多了两个独有属性:

  • functionContext
  • functionOptions

6.2 VNode有什么作用

渲染视图时,先模拟真实的DOM元素创建vnode,使用vnode渲染DOM节点,在每次渲染时,先将vnode缓存起来,下一次渲染时,通过比对新旧vnode的不同来修改真实的DOM元素。

你可能感兴趣的:(【一起读】深入浅出Vue.js——虚拟DOM之VNode)