vue原始碼學習——虛擬dom樹是如何定義的
阿新 • • 發佈:2018-12-19
情景:相信通過前面的學習你已經知道了虛擬dom為什麼會被構思,那麼接下來你好奇的應該是作者該如何定義這個虛擬dom
export default class VNode { tag: string | void;//當前節點的標籤名 data: VNodeData | void;//當前節點對應的物件,包含了一些具體的資料資訊,是一個VNodeData型別,可以參考VNodeData型別中的資料資訊 children: ?Array<VNode>;//當前節點的子節點是一個數組 text: string | void;//當前節點的文字 elm: Node | void;//當前虛擬節點對應的真實dom節點 ns: string | void;//當前節點的名字空間 context: Component | void; // rendered in this component's scope 當前節點的編譯作用域 functionalContext: Component | void; // only for functional component root nodes函式化元件作用域 key: string | number | void;//節點的key屬性,被當作節點的標誌,用以優化 componentOptions: VNodeComponentOptions | void;//元件的option選項 componentInstance: Component | void; // component instance 當前節點對應的元件的例項 parent: VNode | void; // component placeholder node 當前節點的父節點 raw: boolean; // contains raw HTML? (server only) 是否為原生html或只是普通文字,innerHTML的時候為true,textContent的時候為false isStatic: boolean; // hoisted static node //是否為靜態節點 isRootInsert: boolean; // necessary for enter transition check //是否作為根節點插入 isComment: boolean; // empty comment placeholder? //是否為註釋節點 isCloned: boolean; // is a cloned node? //是否為克隆節點 isOnce: boolean; // is a v-once node? //是否有v-once屬性 constructor ( tag?: string, data?: VNodeData, children?: ?Array<VNode>, text?: string, elm?: Node, context?: Component, componentOptions?: VNodeComponentOptions ) { /*當前節點的標籤名*/ this.tag = tag /*當前節點對應的物件,包含了具體的一些資料資訊,是一個VNodeData型別,可以參考VNodeData型別中的資料資訊*/ this.data = data /*當前節點的子節點,是一個數組*/ this.children = children /*當前節點的文字*/ this.text = text /*當前虛擬節點對應的真實dom節點*/ this.elm = elm /*當前節點的名字空間*/ this.ns = undefined /*編譯作用域*/ this.context = context /*函式化元件作用域*/ this.functionalContext = undefined /*節點的key屬性,被當作節點的標誌,用以優化*/ this.key = data && data.key /*元件的option選項*/ this.componentOptions = componentOptions /*當前節點對應的元件的例項*/ this.componentInstance = undefined /*當前節點的父節點*/ this.parent = undefined /*簡而言之就是是否為原生HTML或只是普通文字,innerHTML的時候為true,textContent的時候為false*/ this.raw = false /*靜態節點標誌*/ this.isStatic = false /*是否作為跟節點插入*/ this.isRootInsert = true /*是否為註釋節點*/ this.isComment = false /*是否為克隆節點*/ this.isCloned = false /*是否有v-once指令*/ this.isOnce = false } // DEPRECATED: alias for componentInstance for backwards compat. /* istanbul ignore next */ get child (): Component | void { return this.componentInstance } }
- 具體舉例應用
{
tag: 'div',
data: {
class: 'test'
},
children: [
{
tag: 'span',
data: {
class: 'demo'
}
text: 'hello'
}
]
}
渲染的結果
<div class="test"> <span class="demo">hello</span> </div>
- 建立一個空節點的方法(一個空節點對頁面沒有任何影響)
export const createEmptyVNode = (text: string = '') => {
const node = new VNode()
node.text = text
node.isComment = true //空節點沒有任何影響所以可以被註釋掉
return node
}
- 建立一個文字節點
export function createTextVNode (val: string | number) { return new VNode(undefined, undefined, undefined, String(val)) //一般構造器裡傳8個引數 }
- cloneVNode克隆一個VNode節點
export function cloneVNode (vnode: VNode): VNode {
const cloned = new VNode(
vnode.tag,
vnode.data,
vnode.children,
vnode.text,
vnode.elm,
vnode.context,
vnode.componentOptions,
vnode.asyncFactory
//構造器裡面有7個引數,這個引數不是必傳的為何出現在這裡
)
cloned.ns = vnode.ns
cloned.isStatic = vnode.isStatic
cloned.key = vnode.key
cloned.isComment = vnode.isComment
cloned.fnContext = vnode.fnContext
cloned.fnOptions = vnode.fnOptions
cloned.fnScopeId = vnode.fnScopeId
cloned.asyncMeta = vnode.asyncMeta
cloned.isCloned = true
return cloned
//下面的引數沒有ssrContext、isAsyncPlaceholder、isOnce、isRootInsert、raw
}
- 雖然原始碼的這個vnode.js看懂了,可是作者的構造器和克隆函式為什麼要這麼設計呢
這個問題還需要進一步研究,繼續加油
- 或許你會問這個節點為什麼就能在頁面上顯示出來
當然還有一部分js操作了html的程式碼沒有被展示出來,如果你還想繼續瞭解可以再繼續研究原始碼