- vue實例渲染的底層實現
- vue實例生命周期
- vue實例渲染的生命周期與鈎子函數詳解
一、vue實例渲染的底層實現
1.1實例掛載
在vue中實例掛載有兩種方法:第一種在實例化vue時以el屬性實現,第二種是通過vue.$mount()方法實現掛載。不管是哪種掛載都不影響vue實例化組件的執行流程和模式,只是通過vue.$mount()方法實現掛載可以更靈活的實現組件復用和掛載。
1 var vm = new Vue({ 2 el:'掛載元素id',//實例化el屬性實現掛載 3 ... 4 }) 5 var vm1 = new Vue({...}); 6 vm1.mount('掛載元素id');//vue.mount()方法實現掛載 7 //參數模型:# + id
1.2構建DOM抽象語法樹與template
在vue實例化中有一個非常關鍵的操作就是構建DOM抽象語法樹,基於抽象語法樹生成虛擬節點,然后再將數據渲染到虛擬節點上,再將完成數據渲染的節點添加到document中刷新頁面,呈現頁面效果。構建抽象語法樹有三種方式:1.基於綁定的實例化屬性el和$mount()方法構建;2.基於實例化屬性template添加的模板構建;3.基於ready()的參數構建。
這三種構建方式的優先級:render() > template > el
本質上的el與template與render()函數的參數都是一個原理,通過el就是將el指向的元素的DOM模型的outerHTML屬性值拿到,outerHTML屬性值與template的形式完全一樣就是html文本的字符串形式;然后將這個字符串形式的html文本轉換成js對象模型,render()函數中使用的就直接是js對象模型,接着通過js對象模型所表達的html結構轉換成AST(抽象語法樹)用於構建虛擬節點VNode;render()函數再在這個虛擬節點上渲染數據,完成數據渲染后就添加到html文檔中渲染到頁面。
通過元素在window上的id指向獲取到id匹配的元素節點對象的outerHTML屬性值:
1 <div id="app">我是一個div</div> 2 <script> 3 console.log(app.outerHTML);//"<div id="app">我是一個div</div>" 4 </script>
通過vue對象實例化屬性template構建vue實例:
1 <div id="app">我是一個div</div> 2 <script> 3 var vm = new Vue({ 4 el:"#app", 5 template:`<div>我是template模板構建的節點</div>` 6 }) 7 </script>
通過vue實例化將實例化對象屬性template的模板替代app指向的原節點,實質上是在vue實例構建過程中如果發現有template就不會再去獲取掛載節點的結構了。接着再來看看render()方法如何實現vue實例構建:
<div id="app">我是一個div</div> <script> var vm = new Vue({ el:"#app", template:`<div>我是template模板構建的節點</div>`, render(createElement){ return createElement("p"); } }) </script>
通過添加render()方法刷新頁面會發現頁面變成了空白,也就是說el掛載原節點和template模板構建的節點都沒生效,查看瀏覽器控制台可以看到在原app指向的節點的位置被一個空的p標簽替代了。這就是說render()函數的優先級大於template和el,但是要注意的是vue實例化必須是在通過el或者vue.mount()掛載才會去執行render()節點渲染方法,不然一個不掛載的vue實例有何必要渲染呢?
1.3基於JS對象模型的AST抽象語法樹構建及虛擬節點渲染:
render(createElement){
return createElement(ElementName,ElementProperty,ChildNode);
}
這里不深入討論render的設計實現,也不討論虛擬節點的具體底層實現原理,也不深入探究render的復雜應用,僅僅對render()函數基於js對象模型構建AST抽象語法樹做出解析。
createElement:聲明工具函數的名稱;
ElementName:設定抽象語法樹根節點元素名稱;
ElementProperty:設定根節點元素的屬性;
ChildNode:設定子節點;
1 render(createElement){ 2 return createElement("p",{ 3 style:{ 4 color:"red", 5 fontSize:'18px' 6 }, 7 class:['classname1','classname2'] 8 },"我是由render構建的p標簽"); 9 }
基於data的構建方式:

1 <div id="app">我是一個div</div> 2 <script> 3 var vm = new Vue({ 4 el:"#app", 5 template:`<div>我是template模板構建的節點</div>`, 6 data:{ 7 classname1:true, 8 classname2:false, 9 text:'我時由render構建的p標簽' 10 }, 11 render(createElement){ 12 return createElement("p",{ 13 style:{ 14 color:"red", 15 fontSize:'18px' 16 }, 17 class:{//基於數據綁定class 18 classname1:this.classname1, 19 classname2:this.classname2 20 } 21 },this.text); 22 } 23 }) 24 </script>
使用createElement工具方法迭代子節點(在前面的子節點都直接使用字符串,就是說明其是文本節點,使用createElement可以創建元素子節點):
1 <div id="app">我是一個div</div> 2 <script> 3 var vm = new Vue({ 4 el:"#app", 5 template:`<div>我是template模板構建的節點</div>`, 6 data:{ 7 classname1:true, 8 classname2:false, 9 text:'我時由render構建的p標簽' 10 }, 11 render(createElement){ 12 return createElement("p",{ 13 style:{ 14 color:"red", 15 fontSize:'18px' 16 }, 17 class:{//基於數據綁定class 18 classname1:this.classname1, 19 classname2:this.classname2 20 } 21 },[ 22 '我是一個文本節點', 23 createElement('h1','我是h1標簽'), 24 createElement('h2',{ 25 style:{ 26 color:'orange' 27 } 28 },'我是h2標簽') 29 ]); 30 } 31 }) 32 </script>
其實本質上render()函數與頁面渲染中的抽象語法樹構建是異曲同工,一個是基於js對象參數構建,一個是通過html文檔構建;一個是在js中完成一個是在瀏覽器底層渲染模型中完成。
二、vue實例生命周期與鈎子函數
更多的鈎子函數相關內容可以參考這篇博客: https://www.jianshu.com/p/3e91a1c42397
三、vue實例渲染的生命周期與鈎子函數詳解
Vue 渲染底層原理之render函數·Vue 實例生命周期與鈎子函數
______________________________________________________________________________
| Init Events & Lisfecyde:初始化創建vue實例需要的相關事件與實例化生命周
| 期需要的函數。
|
|____①___beforeCreate():初始化vue實例之前執行的鈎子函數。
|
| Init injections & reactivity:初始化實例,將實例參數:el、data、methods等
| 添加到實例對象上,為構建虛擬DOM做好准備。
|
|____②___created():初始化vue實例之后執行的鈎子函數。
| 構
| 建 el、$mount(el):判斷實例是通過哪種掛載方法。
| 抽 判斷是否采用template模板,還是通過元素的outerHTML屬性構建抽象語法
| 象 樹。(所以在這之前需要判斷是通過哪種方式掛載,如果沒有模板就需要基於
| 語 掛載的node結構來構建抽象語法樹)
| 法
| 樹
|____③___beforeMount():渲染頁面之前執行的鈎子函數。
|
| Create vm.$el and replace “el” with it:基於抽象語法樹與數據構建虛擬node,
| 並將虛擬node渲染到頁面,形成HTML文檔,如果之前在HTML中包含定義
| 結構的元素(包含自定義元素)會被替換。(渲染頁面包含三個步驟:構建虛
| 擬節點、刪除原文節點、插入新的文件節點)
|
|____④___mounted():渲染頁面之后執行的鈎子函數。
|
|________________________________________________________________________
| |
|____⑤___beforeUpdate():重新渲染之前觸發的鈎子函數。 |
| |
| Mounted(觸發重新渲染—數據迭代更新) |
| |
|____⑥___update():重新渲染之后觸發的渲染函數。 |
| |
|_________________________________________________________________________| |
|
|____⑦___beforeDestroy():實例銷毀前觸發的鈎子函數。
|
| Teardown watchers, child components and event listeners:拆卸監
| 視器、子組件和事件偵聽器。)
| Destroy【銷毀實例】
|
|____⑧___destroyed():實例銷毀后執行的鈎子函數。