大概幾集下飯劇時間就能懂的 VUE3 原理
大概幾集下飯劇時間就能懂的 VUE3 原理
大家好,我是卡頌。
最近中午沒胃口,找來VUE
源碼相關視頻來當下飯劇。幾頓飯下去,人胖了,VUE
也整明白了。
這篇文章爲你帶來一份VUE3
原理速成指南。
模塊劃分
如果我們用**「VUE 的模版語法」**定義:
<div>hello</div>
最終VUE
會幫我們在瀏覽器中渲染對應的DOM節點
。
這之間對這段節點的描述會經歷 4 次變化,橫跨**「編譯時」**與**「運行時」**:
「模版語法」在編譯時會被「編譯器」轉化爲「render 函數」,類似:
render(h) {
return h('div', 'hello');
}
在運行時,**「render 函數」執行後返回的「h 函數的執行結果」**就是VNode
(也就是虛擬DOM
),類似:
{
tag: "div",
children: [
{
text: "Hello"
}
]
}
最終,VUE
根據VNode
的信息,在瀏覽器渲染對應DOM
。
那麼,是誰在驅動這一流程?
mount 和 patch
組件有兩種不同的渲染邏輯:「首次渲染」和「更新」。
**「首次渲染」**意味着從無到有,比如上文的VNode
:
{
tag: "div",
children: [
{
text: "Hello"
}
]
}
可能對應如下DOM
操作:
const node = document.createElement(VNode.tag);
node.textConent = 'Hello';
contanerDOM.appendChild(node);
**「更新」**則需要對比更新前後VNode
,對變化部分執行DOM
操作。
比如,以上VNode
如果變爲:
{
tag: "div",
children: [
{
// text改變
text: "world"
}
]
}
則最終執行:
node.textContent = 'world';
VUE
的**「首次渲染」**對應mount
模塊,**「更新」**對應patch
模塊。
所以,render函數
執行後返回VNode
,根據情況不同,會走mount
或patch
的渲染邏輯:
如果想深入
虛擬DOM
相關知識,推薦閱讀 snabbdom[1] 源碼。這是個優秀的虛擬 DOM 庫,VUE2
的虛擬DOM
部分就是fork
這個庫改造的。
那麼是誰在什麼時機調用了render函數
呢?
響應式更新
在VUE
中,狀態變化會實時反映到視圖上,比如:
<div @click="count++">{{count}}</div>
點擊div
後:
-
觸發點擊事件,
count
變化 -
count
變化觸發回調,回調中更新視圖
當前我們已經知道第二步是由於觸發瞭如下流程:
所以只需要建立count
變化到執行render函數
的聯繫即可。
具體來說,我們希望實現reactive
及watchEffect
:
// 定義狀態
const state = reactive({count: 0});
// 監聽狀態變化
watchEffect(() => {
console.log(state.count);
})
// 改變狀態
state.count++;
reactive
定義狀態。
watchEffect
根據回調執行的情況決定監聽哪些狀態。
比如watchEffect
回調執行了console.log(state.count);
,他就會監聽state
的變化。
當執行state.count++;
,由於watchEffect
監聽了state
的變化,則其回調會觸發,打印state.count
。
這就是Reactivity
模塊。
VUE 官方推出了 VUE3 響應式原理 [2] 課程講解
Reactivity
的實現,這是 B 站鏈接。如果經濟允許,請支持正版 [3]
當實現了Reactivity
模塊,我們就能將**「組件狀態」**與後續流程串聯起來。
剛纔講過,render函數
是編譯器根據**「模版語法」**生成的。在面對帶狀態的模版語法時,比如上文的count
:
<div @click="count++">{{count}}</div>
render函數
內的count
是響應式的(即:count
實際是reactive({count: 0})
)。
那麼就能用watchEffect
監聽count
的變化。
所以,在應用初始化時,會有類似邏輯:
let isMounted = false;
let oldVNode;
watchEffect(() => {
if (!isMounted) {
// mount邏輯
// 調用render函數
oldVNode = component.render();
// mount
mount(oldVNode);
} else {
// patch邏輯
// 調用render函數
newVNode = component.render();
patch(oldVNode, newVNode);
oldVNode = newVNode;
}
})
其中component.render()
(render 函數的執行)達到上文**「監聽狀態變化」**的效果:
// 監聽狀態變化
watchEffect(() => {
console.log(state.count);
})
所以,該組件內任何狀態變化都會觸發watchEffect
的執行,watchEffect
回調內會觸發後續流程。
總結
VUE3
按原理大體可以劃分爲:
-
mount
-
patch
-
編譯器
-
Reactivity
VUE
官方推出了實現簡易 VUE3 教程 [4],感興趣的朋友可以去看看。如果有能力,記得去支持正版 [5] 哦。
參考資料
[1]
snabbdom: https://github.com/snabbdom/snabbdom
[2]
VUE3 響應式原理: https://www.bilibili.com/video/BV1SZ4y1x7a9/?spm_id_from=333.788.b_7265636f5f6c697374.6
[3]
正版: https://www.vuemastery.com/free-weekend/?gclid=Cj0KCQjwpreJBhDvARIsAF1_BU16x7gElbhGqGzZZ1geo5RzOqz_PuaJzBM41jHcAAC6CPwPSPvo8G8aAkdhEALw_wcB
[4]
實現簡易 VUE3 教程: https://www.bilibili.com/video/BV1rC4y187Vw?p=10
[5]
正版: https://www.vuemastery.com/free-weekend/?gclid=Cj0KCQjwpreJBhDvARIsAF1_BU16x7gElbhGqGzZZ1geo5RzOqz_PuaJzBM41jHcAAC6CPwPSPvo8G8aAkdhEALw_wcB
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/fsyqkj5FhjHxzMLw9MgjZQ