什麼是模板編譯?以下這篇文章帶大家聊聊vue中的模板編譯,探討一下模板編譯原理,希望對大家有幫助!
vue提供了範本語法,讓我們可以宣告式地描述狀態和DOM之間的綁定關係,例如<p>{{name}} </p>
<p></p>
。
模板編譯指的是模板將編譯成render函數的過程,而渲染函數的作用是每次執行時,會根據最新狀態產生新的vnode。
編譯的過程是:模板作為輸入-> 模板編譯階段->產生渲染函數
解析器
:將模板解析為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>
解析器-將模板解析成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
出戰
標記靜態子樹的好處
#优化器的内部实现主要分两步用递归的方式将所有节点添加 static 属性,true表示是静态的,false表示不是静态的。
静态根节点也是静态节点
如果一个静态根节点的子节点只有一个文本节点或没有子节点,那么不会标记成静态根节点,即使他们是,因为优化成本大于收益
怎么判断是否静态节点?
在将模板字符串解析成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學習之聊模板編譯原理的詳細內容。更多資訊請關注PHP中文網其他相關文章!