vue入門:(底層渲染實現render函數、實例生命周期)


  • 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>
View Code

使用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():實例銷毀后執行的鈎子函數。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM