什么是VNode

在Vue.js中存在一个VNode类,使用它可以实例化不同类型的vnode实例,而不同类型的vnode实例各自表示不同类型的DOM元素,例元素节点,文本节点或者是注释节点。
VNode类的代码:

export default class VNode{
    constructor(tag...){    
        this.tag = tag
        this.data = data
        this.children = children
        this.text = text
        ......
    }
}

vnode事实上只是一个普通的js对象,是从Vnode类实例化的对象,用这个来描述某个真实DOM元素,那么该DOM元素上的所有属性都应该在VNode这个对象上都存在对应的属性。可以将vnode理解为节点描述对象,是JavaScript对象版本的DOM元素

VNode的作用

每次创建vnode后,在渲染视图时都要缓存起来,以便之后需要重新渲染的时候,可以利用新老vnode进行比对来查找出不同的地方,基于此来修改真实的DOM。
现在对状态的侦测采用中等粒度,所以当状态发生变化的时候,只通知到组件级别,当组件中的任何一个状态发生变化,需要对整个组件进行重新渲染,如果只有一个发生变化,重新渲染整个组件会造成很大的性能浪费,所以对vnode进行缓存,利用新老vnode进行比对,只修改更新变化后的节点就变得很重要。

VNode的类型

注释节点/文本节点/元素节点/组件节点/函数式组件/克隆节点
vnode在不同类型节点之间其实就是属性不同,在创建成vnode的时候,通过参数为实例设置属性,无效的属性会被设置为undefined或false,只在意节点的有效属性即可。

1.注释节点

<! -- 注释节点 -->
//创建注释节点
export const createEmptyVNode = text =>{
    const node = new VNode()
    node.text = text //注释的文本内容
    node.isComment = true  //是否是注释
    return node
}

2.文本节点

export function createTextVNode(val){
    return new VNode(undefined,undefined,undefined,String(val))
}

{
    text:'Hello World'
}

文本节点只有一个text属性

3.克隆节点

克隆节点是将现有节点的属性复制到新节点中,让新创建的节点和被克隆节点的属性保持一致,达到克隆效果。作用是用来优化静态节点和插槽节点(slot node)
静态节点在第一次渲染时所需要获取vnode之外,之后更新不需要重新渲染生成vnode,所以此时会使用创建克隆节点,将vnode静态节点克隆一份,使用克隆节点进行渲染,就不需要重新生成渲染函数来生成新的静态节点,从一定程度上提升了性能。
克隆现有节点时,只需要将现有的节点属性全部复制到新节点之中即可。克隆节点和被克隆节点之间唯一的区别就是isCloned属性,克隆节点为true,被克隆的原始节点为false。

4.元素节点

元素节点通常会存在4种有效属性
1.tag:节点的名称。例如p,div,li等等
2.data:包含了一些节点上的数据。例如attrs,class,style等等
3.chidren:当前节点的子节点列表。
4.context:它时当前组建的Vue.js实例

//例如一个真实的元素节点
<p><span>Hello</span><span>World!</span></p>
//所对应的vnode
{
    children:[VNode,VNode]
    context:{...},
    data:{...},
    tag:"p",
    ......
}

5.组件节点

组件节点有两个一下独有的属性
componentOptions:组件节点的选项参数,其中包含propsData、tag和children等信息
componentInstance:组件的实例,也是Vue.js的实例。每一个组件都是一个Vue.js实例。

//一个组件节点
<child></child>
{
    componentInstance:{...},
    componentOptions:{...},
    context:{...},
    data:{...},
    tag:"vue-component-1-child",
    ......
}

6.函数式组件

函数式组件和组件节点类似,有两个独有属性
functionalContext和functionalOptions

总结

Vnode是一个类,可以生成不同类型的vnode实例,而不同类型的vnode表示不同类型的真实DOM元素。
由于Vue.js对组件采用了虚拟DOM来更新视图,当属性发生变化时,整个组件都要进行重新渲染的操作,但组件内并不是所有的DOM节点都需要更新,所以将vnode缓存并将当前新生成的vnode和上一次缓存的oldVnod进行对比,只对需要更新的部分进行DOM操作可以提升更多的性能。
vnode有很多类型,它们本质上都是从VNode类实例化出的对象,其唯一区别就是属性不同。