深入浅出Vue.js阅读——虚拟DOM——VNode

VNode

1. 什么是VNode

  在Vue.js中存在一个VNode类,使用它可以实例化不同类型的vnode实例,而不同类型的vnode实例各自表示不同类型的DOM元素。
  vnode只是一个名字,本质上其实是JavaScript中的一个普通对象,是从VNode类实例化的对象。我们用这个JavaScript对象来描述一个真实的DOM元素,那么该DOM元素上的所有属性在VNode这个对象上都存在对应的属性。

export default class VNode{
    constructor(tag,data,children,text,elm,context,componentOptions,asyncFactory){
        this.tag= tag;
        this.data = data;
        this.children= children;
        this.text = text;
        this.elm = elm;
        this.context = context;
        this.componentOptions = componentOptions;
        this.asyncFactory = asyncFactory;
        this.ns = undefined;
        this.functionalContext = undefined;
        this.funtionalOptions = undefined;
        this.functionalScopeId = undefined;
        this.key = data && data.key;
        this.parent = undefined;
        this.componentInstance = undefined;
        this.raw = false;
        this.isStatic = false;
        this.isRootInsert = true;
        this.isComment = false;
        this.isCloned = false;
        this.isOnce = false;
        this.asyncMeta = undefined;
        this.isAsyncPlaceholder = false;
    }

    get child (){
        return this.componentInstance;
    }
}

  vnode可以理解成节点描述对象,它描述了应该怎样去创建真实的DOM节点。我们可以把vnode理解成JavaScript对象版本的DOM元素。
  渲染视图的过程是先创建vnode,然后使用vnode去生成真实的DOM元素,最后插入到页面渲染视图。

2. 作用

  只要组件的众多状态中有一个发生了变化,那么整个组件就要重新渲染。因此,对vnode进行缓存,并将上一次缓存的vnode和当前新创建的vnode进行对比,只更新发生变化的节点就尤为重要。

3. VNode的类型

1. 注释节点

  注释节点只有两个有效属性:textisComment,其余属性全是默认的undefinedfalse:

export const createEmptyVNode = text =>{
    const node = new VNode();
    node.text = text;
    node.isComment = true;
    console.log(node);
}

一个真实的注释节点:

<!--注释节点-->

对应的vnode是这样的:

{
    text:"注释节点",
    isComment:true
}

2. 文本节点

  文本节点类型的vnode被创建时,它只有一个text属性:

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

文本类型的vnode:

{
    text:"hello word"
}

3. 克隆节点

  克隆节点是将现有节点的属性复制到新节点中,让新创建的节点和被克隆的节点属性保持一致,从而实现克隆效果。作用是优化静态节点和插槽节点(slot node)。
  克隆现有节点时,只需要将现有节点的属性全部复制到新节点中即可。

/* 克隆节点 */
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 = true;
    if(deep && vnode.children){
        cloned.children = cloneVNode(vnode.children);
    }
    return cloned;
}

  克隆节点和被克隆节点之间唯一的区别是isCloned属性,克隆节点的isClonedtrue,被克隆的原始节点的isClonedfalse

4. 元素节点

  元素节点通常会存在一下4种有效属性:

  • tag:就是一个节点的名称,例如:p、ul、li和div等。
  • data:该属性包含了一些节点上的数据,比如attrsclassstyle
  • children:当前节点的子节点列表。
  • context:当前组件的Vue.js实例。
    例如,这是一个真实的元素节点:
<p>
   <span>Hellospan><span>Wordspan>
p>

对应的vnode是这样的:

{
    children:[VNode,VNode],
    context:{...},
    data:{...},
    tag:"p",
    // ...
}

5. 组件节点

  组件节点有一下两个独有属性:

  • componentOptions:组件节点的选项参数,其中包含propsDatatagchildren等信息。
  • componentInstance:组件的实例,也是Vue.js的实例。事实上,在Vue.js种,每个组件都是一个Vue.js实例。
    一个组件节点:
<child>child>

对应的vnode是这样的:

{
    componentInstance:{...},
    componentOptions:{...},
    context:{...},
    data:{...},
    tag:"vue-component-1-child",
    // ...
}

6. 函数式组件

  函数式组件和组件节点类似,它有两个独有的属性functionalContextfunctionalOptions
组件的vnode是这个样子的:

{
    functionalContext:{...},
    functionalOptions:{...},
    context:{...},
    data:{...},
    tag:"div",
}

4. 总结

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

你可能感兴趣的:(深入浅出Vue.js阅读,vue)