您好,登錄后才能下訂單哦!
這篇文章主要介紹了vue模板編譯的原理是什么的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇vue模板編譯的原理是什么文章都會有所收獲,下面我們一起來看看吧。
vue提供了模板語法,允許我們聲明式地描述狀態和DOM之間的綁定關系,比如<p>{{name}}<p>
。
模板編譯指的是模板將編譯成render函數的過程,渲染函數的作用是每次執行時,會根據最新狀態生成新的vnode。
編譯的過程是:模板作為輸入 -> 模板編譯 階段->生成 渲染函數
vue的模板編譯?
模板編譯Compiler中render講解?
vue 模板編譯的過程,每一個過程細說一下做了些什么
模板編譯,誰去解析AST樹 【相關推薦:vuejs視頻教程、web前端開發】
解析器
:將模板解析為AST(Abstract Syntax Tree 抽象語法樹)
優化器
:遍歷AST標記靜態節點,因為靜態節點不可變,不需要為打上標簽的靜態節點創建新的虛擬節點,直接克隆已有的虛擬節點。
代碼生成器
:使用AST生成渲染函數。將AST轉換成代碼字符串。將代碼字符串放入渲染函數中,導出被外界使用。
假設如下代碼,有el
、template
、render
、$mount
//復雜案例
let vue = new Vue({
el: '#app',
data() {
return {
a: 1,
b: [1]
}
},
render(h) {
return h('div', { id: 'hhh' }, 'hello')
},
template: `<div id='hhh' style="aa:1;bb:2"><a>{{xxx}}{{ccc}}</a></div>`
}).$mount('#app')
console.log(vue)
//腳手架創建的案例
let vue = new Vue({
render: h => h(App)
}).$mount('#app')
1)渲染到哪個根節點上:判斷有無el屬性,有的話直接獲取el根節點,沒有的話調用$mount時去獲取根節點
2)渲染哪個模板到根節點上去:是否調用render
函數傳入了模板 render: h => h(App) -> <App></App>
有render:這時候優先執行render函數,render優先級 > template
無render:
有template:template解析成render函數的所需格式-代碼字符串,并使用調用render函數渲染
無template:el根節點的outerHTML解析成render函數的所需格式-代碼字符串,并使用調用render函數渲染
3.渲染的方式:無論什么情況,最后都統一是要使用render函數渲染
解析器-將模板解析成AST
<div>
<p>{{name}}</p>
</div>
將上述模板解析成AST后,AST抽象語法樹就是使用JS中的對象來描述一個節點,一個對象表示一個節點。
{
tag: "div"
type: 1, //節點類型
staticRoot: false,
static: false,
plain: true,
parent: undefined, //存放父節點
attrsList: [],
attrsMap: {},
children: [ //存放孩子節點
{
tag: "p"
type: 1,
staticRoot: false,
static: false,
plain: true,
parent: {tag: "div", ...},
attrsList: [],
attrsMap: {},
children: [{
type: 2,
text: "{{name}}",
static: false,
expression: "_s(name)"
}]
}
]
}
解析器的原理的是一小段一小段地截取模板字符串,每截取一小段字符串,就會根據截取出來的字符串類型觸發不同的鉤子函數,直到模板字符串截空停止。然后使用棧來確定層級關系
解析器內部分也分幾個子解析器,如HTML解析器、文本解析器等。
HTML解析器的作用是解析HTML,在解析HTML的過程中不斷觸發各種鉤子函數,
開始標簽的鉤子函數中可以構建元素類型的節點
文本鉤子函數中可以構建文本類型的節點
注釋鉤子函數中可以構建注釋類型的節點
結束標簽鉤子函數
文本解析器是對HTML解析出來的文本進行二次加工,比如插值語法{{}}
如何確定DOM之間的層級關系?使用棧
在觸發開始標簽的鉤子函數時,如果當前標簽不是自閉合標簽,就push
進stack
。
在觸發結束標簽的鉤子函數時,就從棧中pop
出戰
標記靜態子樹的好處
每次重新渲染時,不需要為靜態子樹創建新虛擬子樹,克隆已存在的靜態子樹
在虛擬DOM中打補丁(patching)的過程可以跳過 ,靜態子樹是不可變的
優化器的內部實現主要分兩步用遞歸的方式將所有節點添加 static 屬性,true表示是靜態的,false表示不是靜態的。
在AST中找出所有靜態節點并打上標記
靜態節點:DOM不會發生變化的節點
通過遞歸的方式從上向下標記靜態節點,如果一個節點被標記為靜態節點,但它的子節點卻被標記為動態節點,就說明該節點不是靜態節點,可以將它改為動態節點。靜態節點的特征是它的子節點也必須是靜態的。
靜態根節點也是靜態節點
**在AST中找出所有靜態根節點并打上標記 **
靜態根節點:子節點全是靜態節點的節點
使用遞歸從上向下尋找,在尋找的過程中遇見的第一個靜態節點就為靜態根節點,同時不繼續往下找。
如果一個靜態根節點的子節點只有一個文本節點或沒有子節點,那么不會標記成靜態根節點,即使他們是,因為優化成本大于收益
怎么判斷是否靜態節點?
在將模板字符串解析成AST的時候,會根據不同的文本類型設置一個 type
type | 說明 | 是否時靜態節點 |
---|---|---|
1 | 元素節點 | 進行一些排除 |
2 | 帶遍歷的動態文本節點 | 不是 |
3 | 不帶遍歷的純文本節點 | 是 |
代碼生成器的作用:將AST轉化成渲染函數中的代碼字符串
<div>
<p>{{name}}</p>
</div>
//生成的render渲染函數
{
render: `with(this){return _c('div',[_c('p',[_v(_s(name))])])}`
}
//格式化后
with(this){
return _c(
'div',
[
_c(
'p',
[
_v(_s(name))
]
)
]
)
}
生成代碼字符串是一個遞歸的過程,從頂向下依次處理每一個AST節點。
節點有三種類型,分別對應三種不同的創建方法與別名。
類型 | 創建方法 | 別名 |
---|---|---|
元素節點 | createElement | _c |
文本節點 | createTextVNode | _v |
注釋節點 | createEmptyVNode | _e |
渲染函數可以生成VNode的原因:渲染函數其實是執行了createElement,而createElement可以創建VNode。
代碼字符串的拼接過程
遞歸AST來生成字符串,最先生成根節點,然后在子節點字符串生成后,將其拼接在根節點的參數中,子節點的子節點拼接在子節點的參數中,一層層拼接。
關于“vue模板編譯的原理是什么”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“vue模板編譯的原理是什么”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。