runtime
運行時,主要在packages/runtime-core
目錄下,核心提供了h
、render
等函數。在理解它們之前,我們需要了解下HTML DOM 樹
和虛擬 DOM
等概念
HTML DOM 樹
通過節點構成的一個樹形結構,我們稱為HTML DOM
節點樹。DOM 文檔里面做了詳細解釋,這里就不再展開講解,通過以下例子來簡單理解:
<div> <h1>hello h1</h1> <!-- 這里是注釋 --> hello div
</div>
瀏覽器運行上述代碼時,它會生成一個對應的DOM 樹
來展示:
虛擬DOM
虛擬 DOM 是一種編程概念,意為將目標所需的 UI 通過數據結構“虛擬”地表示出來,保存在內存中,然后將真實的 DOM 與之保持同步,詳細解釋可見 Vue文檔
通過以下這個例子來說明:
可以看出虛擬 DOM 類似把真實 DOM 轉換成一個 VNode 對象,該對象存在節點的類型type
、子節點信息children
等屬性,而子節點有可能是字符串,也可能是包含其他子節點的數組
// 真實 DOM
<div>text</div>// 虛擬 DOM 表示
const vnode = {type: 'div', // 父節點類型 divchildren: 'text' // 子節點內容 text
}// 真實 DOM
<div><h1>hello h1</h1><!-- TODO: comment -->hello div
</div>// 虛擬 DOM 表示
const vnode = {type: 'div', // 父節點類型 divchildren: [ // 多個子節點{type: 'h1', // 子節點類型 h1children: 'hello h1' // 子節點內容 hello h1 },{type: Comment, // 子節點類型 Commentchildren: 'TODO: comment' // 子節點內容 TODO: comment },'hello div' // 子節點內容 hello div]
}
而在runtime
運行時,渲染器render
會遍歷整個虛擬 DOM 樹,并據此構建真實的 DOM 樹,這個過程把它叫做掛載mount
當這個VNode
對象發生變化時,那么我們會對比舊的 VNode
和新的 VNode
之間的區別,找出它們之間的區別,并應用這其中的變化到真實的 DOM 上,這個過程被稱為更新patch
h
Vue
中轉換為VNode
對象就是通過h
函數來完成的,通過調試來看下h
函數的返回值:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><script src="../../dist/vue.global.js"></script></head><body><div id="app"></div><script>const { h } = Vuedebuggerconst vnode = h('div',{class: 'test'},'hello render')console.log(vnode)</script></body>
</html>
h
函數定義在packages/runtime-core/src/h.ts
文件中,它接收三個參數:
type: string | Component
:既可以是一個字符串(用于原生元素),也可以是一個 Vue 組件定義props?: object | null
:要傳遞的 propchildren?: Children | Slot | Slots
:子節點
該 vnode 如下:
最終VNode
對象通過render
函數渲染為真實 DOM,該render
函數定義在packages/runtime-core/src/renderer.ts
文件中,實際執行的是createRenderer
方法,它接收兩個參數:
vnode
虛擬節點樹,或者叫做虛擬 DOM 樹container
承載的容器,真實節點渲染的位置