## 什么是VNode
我們知道,render function 會被轉化成 VNode 節點。Virtual DOM 其實就是一棵以 JavaScript 對象(VNode 節點)作為基礎的樹,用對象屬性來描述節點,實際上它只是一層對真實 DOM 的抽象。最終可以通過一系列操作使這棵樹映射到真實環境上。由于 Virtual DOM 是以 JavaScript 對象為基礎而不依賴真實平臺環境,所以使它具有了跨平臺的能力,比如說瀏覽器平臺、Weex、Node 等。
## 實現一個VNode
VNode 歸根結底就是一個 JavaScript 對象,只要這個類的一些屬性可以正確直觀地描述清楚當前節點的信息即可。我們來實現一個簡單的 `VNode` 類,加入一些基本屬性,為了便于理解,我們先不考慮復雜的情況。
```
class VNode {
constructor (tag, data, children, text, elm) {
/*當前節點的標簽名*/
this.tag = tag;
/*當前節點的一些數據信息,比如props、attrs等數據*/
this.data = data;
/*當前節點的子節點,是一個數組*/
this.children = children;
/*當前節點的文本*/
this.text = text;
/*當前虛擬節點對應的真實dom節點*/
this.elm = elm;
}
}
```
比如我目前有這么一個 Vue 組件。
```
<template>
<span class="demo" v-show="isShow">
This is a span.
</span>
</template>
```
用 JavaScript 代碼形式就是這樣的。
```
function render () {
return new VNode(
'span',
{
/* 指令集合數組 */
directives: [
{
/* v-show指令 */
rawName: 'v-show',
expression: 'isShow',
name: 'show',
value: true
}
],
/* 靜態class */
staticClass: 'demo'
},
[ new VNode(undefined, undefined, undefined, 'This is a span.') ]
);
}
```
看看轉換成 VNode 以后的情況。
```
{
tag: 'span',
data: {
/* 指令集合數組 */
directives: [
{
/* v-show指令 */
rawName: 'v-show',
expression: 'isShow',
name: 'show',
value: true
}
],
/* 靜態class */
staticClass: 'demo'
},
text: undefined,
children: [
/* 子節點是一個文本VNode節點 */
{
tag: undefined,
data: undefined,
text: 'This is a span.',
children: undefined
}
]
}
```
然后我們可以將 VNode 進一步封裝一下,可以實現一些產生常用 VNode 的方法。
* 創建一個空節點
```
function createEmptyVNode () {
const node = new VNode();
node.text = '';
return node;
}
```
* 創建一個文本節點
```
function createTextVNode (val) {
return new VNode(undefined, undefined, undefined, String(val));
}
```
* 克隆一個 VNode 節點
```
function cloneVNode (node) {
const cloneVnode = new VNode(
node.tag,
node.data,
node.children,
node.text,
node.elm
);
return cloneVnode;
}
```
總的來說,VNode 就是一個 JavaScript 對象,用 JavaScript 對象的屬性來描述當前節點的一些狀態,用 VNode 節點的形式來模擬一棵 Virtual DOM 樹。
注:本節代碼參考[《實現 Virtual DOM 下的一個 VNode 節點》](https://github.com/answershuto/VueDemo/blob/master/%E3%80%8A%E5%AE%9E%E7%8E%B0%20Virtual%20DOM%20%E4%B8%8B%E7%9A%84%E4%B8%80%E4%B8%AA%20VNode%20%E8%8A%82%E7%82%B9%E3%80%8B.js)。