深入浅出Vue.js----VNode

一、什么是VNode

(1)Vue.js中存在一个VNode类,使用它可以实例化不同类型的vnode实例,而不同类型的vnode实例各自表示不同类型的DOM元素。

(2)其实vnode只是一个名字,本质上其实是Javascript中一个普通的对象,是从VNode类实例化的对象。我们用这个Javascript对象来描述一个真实DOM元素的话,那么该DOM元素上的所有属性在VNode这个对象上都存在对应的属性。

(3)vnode可以理解成节点描述对象,它描述了应该怎样去创建真实的DOM节点。例如tag表示一个元素节点的名称,text表示一个文本节点的文本,children表示子节点等。

(4)vnode表示一个真实的DOM元素,所有真实的DOM节点都使用vnode创建并插入到页面中。(vnode=》DOM=》视图)

(5)vnode和视图是一一对应的。我们可以把vnode理解成Javascript对象版本的DOM元素。

(6)渲染视图的过程是先创建vnode,然后再使用vnode去生成真实的DOM元素,最后插入页面渲染视图。

二、VNode的作用

(1)由于每次渲染视图时都是先创建vnode,然后使用它创建真实DOM插入到页面中,所以可以将上一次渲染视图时所创建的vnode缓存起来,之后每当需要重新渲染视图时,将新创建的vnode和上一次缓存的vnode进行对比,查看它们之间有哪些不一样的地方,找出这些不一样的地方并基于此去修改真实的DOM。

(2)Vue.js目前对状态的侦测策略采用了中等粒度。当状态发生改变时,只通知到组件级别,然后组件内使用虚拟DOM来渲染视图。

(3)当某个状态发生改变时,只通知使用了这个状态的组件

(4)只要组件使用的众多状态中有一个发生了变化,那么整个组件就要重新渲染。

三、Vnode的类型

(1)vnode的类型

注释节点

文本节点

元素节点

组件节点

函数式组件

克隆节点

(2)vnode是Javascript中的一个对象,不同类型的vnode之间其实只是属性不同,准确地说是有效属性不同。因为当使用VNode类创建一个vnode时,通过参数为实例设置属性时,无效的属性会默认被赋值为undefined或false。对于vnode身上无效属性,直接忽略就好。

  • 注释节点

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

(1)一个注释节点只有两个有效属性-----textisComment,其余属性全是默认的undefined或则false。

// 注释节点

//对应的vnode如下:
{
    text:"注释节点",
    isComment:true
}
  • 文本节点

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

(1)文本类型的vnode被创建时,它只有一个text属性

//文本类型的vnode
{
    text:"Hello Berwin"
}
  • 克隆节点

(1)克隆节点是将现有节点的属性赋值到新节点中,让新创建的节点和被克隆的节点的属性保持一致,从而实现克隆效果。

(2)作用:优化静态节点和插槽节点(slot node)

(3)以静态节点为例,当组件内的某个状态发生变化后,当前组件会通过虚拟DOM重新渲染视图,静态节点因为它的内容不会改变,所以除了首次渲染需要执行渲染函数获取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.;
    cloned.isStatic = vnode.isStatic;
    cloned.key = vnode.key;
    cloned.isComment = vnode.isComment;
    cloned.isCloned = true;
    if(deep&&vnode.children){
        cloned.chlidren = cloneVNodes(vnode.children);
    }
    return cloned;
}

(4)克隆现有节点时,只需要将现有节点的属性全部赋值到新节点中即可。

(5)克隆节点和被克隆节点之间的唯一区别是isCloned属性,克隆节点的isCloned为true,被克隆的原始节点的isCloned为false。

  • 元素节点

(1)元素节点通常存在以下4种有效属性。

  • tag:tag是一个节点的名称,例如ul、p、li和div等。
  • data:该属性包含了一些节点上的数据,比如attrs、class和style等。
  • children:当前节点的子节点列表。
  • context:它是当前组件的Vue.js实例。

(2)例子

真实的元素节点

<p><span>Hello</span><span>Berwin</span></p>

对应的vnode

{
	children:[VNode,VNode],
	context:{...},
	data:{...},
	tag:"p",
	....
}
  • 组件节点

(1)组件节点和元素节点类似,有以下两个独有的属性

  • componentOptions:组件节点的选项参数,其中包含propsData、tag和children等信息。
  • componentInstance:组件的实例,也就是Vue.js实例。事实上,在Vue.js种,每个组件都是一个Vue.js实例。

(2)例子

一个组件节点

<child></child>

对应的vnode如下:

{
	componentInstance:{...},
	componentOptions:{...},
	context:{...},
	data:{...},
	tag:"vue-component-1-child",
	....
}
  • 函数式组件

(1)函数式组件和组件节点类似,它有两个独有的属性functionalContextfunctionalOptions

(2)通常,一个函数式组件的vnode是下面的样子

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

四、总结

(1)vnode是一个类,可以生成不同类型的vnode实例,而不同类型的vnode表示不同类型的真实DOM元素。

(2)由于Vue.js对组件采用了虚拟DOM来更新视图,当属性发生变化时,整个组件都要进行重新渲染的操作,但组件内并不是所有DOM节点都需要更新,所以将vnode缓存并将当前新生成的vnode和上一次缓存的oldVnode进行对比,只对需要更新的部分进行DOM操作可以提升很多性能。

(3)vnode有多种类型,它们本质上都是从Vnode类实例化出的对象,其唯一区别只是属性不同。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章