vue中指令的編譯過(guò)程

首先生成的 ast 會(huì)加上一些屬性,每個(gè) element 元素可以看作是一個(gè) ast 對(duì)象,整顆 DOM 樹(shù)可以看作是包含依賴(lài)關(guān)系的 ast 對(duì)象。
v-if 指令
源碼在 processIf(element) 函數(shù)里面處理
<span v-if="msg">6</span>(msg)?_c('span',[_v("6")]):_e()let ast = [{type: 1,tag: 'span',attrsList: [],attrsMap: { 'v-if': 'msg' },rawAttrsMap: {},parent: {type: 1,tag: 'div',attrsList: [],attrsMap: {},rawAttrsMap: {},parent: undefined,children: [],plain: true,static: false,staticRoot: false},children: [],if: 'msg',ifConditions: [ { exp: 'msg', block: el } ],plain: true,static: false,staticRoot: false,pre: undefined,ifProcessed: true}]
先 processIf 再 genIf,生成 render:
function genIf (el,state,altGen,altEmpty) {el.ifProcessed = true; // avoid recursionreturn genIfConditions(el.ifConditions.slice(), state, altGen, altEmpty)}function genIfConditions (conditions, // [ { exp: 'msg', block: el } ]state,altGen, // 無(wú)altEmpty // 無(wú)) {if (!conditions.length) {return altEmpty || '_e()'}var condition = conditions.shift();if (condition.exp) {// 主要看這里,通過(guò)三元運(yùn)算符?和:拼接字符串return ("(" + (condition.exp) + ")?" + (genElement(el, state)) + ":" + (genIfConditions(conditions, state, altGen, altEmpty)))} else {return ("" + (genTernaryExp(condition.block)))}}
v-for 指令
源碼在 processFor(element) 函數(shù)里面處理
_l((list), function(item){return _c('span',[_v("6")])})<span v-for="item in list">6</span>let ast = [{type: 1,tag: 'span',attrsList: [],attrsMap: { 'v-for': 'item in list' },rawAttrsMap: {},parent: {type: 1,tag: 'div',attrsList: [],attrsMap: {},rawAttrsMap: {},parent: undefined,children: [],plain: true,static: false,staticRoot: false},children: [],for: 'list',alias: 'item',plain: true,static: false,staticRoot: false,pre: undefined,forProcessed: true}]
我們簡(jiǎn)單想象一下 for 指令需要包裝成一個(gè)函數(shù),方便之后的循環(huán)遍歷,比如下面這樣:
function _l(list, callback) { list.forEach(item => callback(item)) }具體的生成過(guò)程:
function genFor (el,state,altGen, // 無(wú)altHelper // 無(wú)) {var exp = el.for;var alias = el.alias;var iterator1 = el.iterator1 ? ("," + (el.iterator1)) : '';var iterator2 = el.iterator2 ? ("," + (el.iterator2)) : '';// 主要看這里,包裝成一個(gè)function函數(shù)el.forProcessed = true; // avoid recursionreturn ('_l') + "((" + exp + ")," +"function(" + alias + iterator1 + iterator2 + "){" +"return " + ((genElement)(el, state)) +'})'}
v-once 指令
源碼在 processOnce(element) 函數(shù)里面處理
<div>11<span v-once="msg">6</span></div>render: `with(this){return _c('div',[_v("11"),_m(0)])}`,staticRenderFns: [ `with(this){return _c('span',[_v("6")])}` ],let ast = [{type: 1,tag: 'span',attrsList: [],attrsMap: { 'v-once': '' },rawAttrsMap: {},parent: {type: 1,tag: 'div',attrsList: [],attrsMap: {},rawAttrsMap: {},parent: undefined,children: [],plain: true,static: false,staticRoot: false},children: [],once: true,plain: true,static: false,staticInFor: false,staticRoot: false,pre: undefined,onceProcessed: true,staticProcessed: true}]
v-once 只渲染元素和組件一次。隨后的重新渲染,元素/組件及其所有的子節(jié)點(diǎn)將被視為靜態(tài)內(nèi)容并跳過(guò)。這可以用于優(yōu)化更新性能。
function genOnce (el, state) {el.onceProcessed = true;return genStatic(el, state)}function genStatic (el, state) {el.staticProcessed = true;var originalPreState = state.pre;state.staticRenderFns.push(("with(this){return " + (genElement(el, state)) + "}"));state.pre = originalPreState;return ("_m(" + (state.staticRenderFns.length - 1) + (el.staticInFor ? ',true' : '') + ")")}
生成 render 函數(shù)的目的就是為了當(dāng)綁定的變量值發(fā)生改變的時(shí)候,可以重新執(zhí)行 render 函數(shù),最后生成真實(shí)的 DOM,其中_c 和 _v 等等這些輔助函數(shù)就是處理真實(shí) DOM 的函數(shù),關(guān)于 render 函數(shù)生成 DOM 我們之后再分析。
評(píng)論
圖片
表情
