深入淺出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類實例化出的對象,其唯一區別只是屬性不同。

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