vue中ast生成render

我們先使用 vue 的模板編譯庫(kù) vue-template-compiler 驗(yàn)證一下輸出結(jié)果。
const compiler = require('vue-template-compiler')let str = `<div v-if="msg">999</div>`console.log(compiler.compile(str))
發(fā)現(xiàn)包含 ast 和 render 這兩個(gè)屬性。
{ast: {type: 1,tag: 'div',attrsList: [],attrsMap: { 'v-if': 'msg' },rawAttrsMap: {},parent: undefined,children: [ [Object] ],if: 'msg',ifConditions: [ [Object] ],plain: true,static: false,staticRoot: false,ifProcessed: true},render: `with(this){return (msg)?_c('div',[_v("999")]):_e()}`,staticRenderFns: [],errors: [],tips: []}
render 屬性的內(nèi)容是根據(jù) ast 屬性生成的,之前我有文章已經(jīng)講解了 ast 是如何生成的,今天主要分析 render 函數(shù)的生成過(guò)程。
// <div v-if="msg">999</div>with(this){return (msg)?_c('div',[_v("999")]):_e()}
每個(gè)指令的生成過(guò)程都不一樣,if 指令會(huì)使用三元運(yùn)算符,for 指令會(huì)生成一個(gè)新的函數(shù),并且會(huì)使用一些輔助函數(shù) _c 和 _v 等等。
// <div><span v-for="item in list">6</span></div>with(this){return _c('div',_l((list),function(item){return _c('span',[_v("6")])}),0)}
開(kāi)始了解如何生成 render 函數(shù)
function generate (ast,options) {var code = ast ? (ast.tag === 'script' ? 'null' : genElement(ast, options)) : '_c("div")';return {render: ("with(this){return " + code + "}")}}
我們暫時(shí)先了解 genElement 函數(shù),看看如何生成元素的。
function genElement (el, state) {if (el.parent) {el.pre = el.pre || el.parent.pre;}if (el.staticRoot && !el.staticProcessed) {// return genStatic(el, state)} else if (el.once && !el.onceProcessed) {// return genOnce(el, state)} else if (el.for && !el.forProcessed) {// return genFor(el, state)} else if (el.if && !el.ifProcessed) {// return genIf(el, state)} else if (el.tag === 'template' && !el.slotTarget && !state.pre) {// return genChildren(el, state) || 'void 0'} else if (el.tag === 'slot') {// return genSlot(el, state)} else {// component or elementvar code;if (el.component) {// code = genComponent(el.component, el, state);} else {var data;var children = el.inlineTemplate ? null : genChildren(el, state, true);code = "_c('" + (el.tag) + "'" + (data ? ("," + data) : '') + (children ? ("," + children) : '') + ")";}// module transforms//for (var i = 0; i < state.transforms.length; i++) {// code = state.transforms[i](el, code);//}return code}}
在生成元素的過(guò)程中,會(huì)先判斷元素上面的各種指令進(jìn)行分別的處理,指令的生成我們暫時(shí)不討論,我們先看看 genChildren 的處理。
function genChildren (el,state,checkSkip,altGenElement,altGenNode) {var children = el.children;if (children.length) {var gen = altGenNode || genNode;return ("[" + (children.map(function (c) { return gen(c, state); }).join(',')) + "]")}}// genNode 函數(shù)是根據(jù)不同的 type 生成不同的內(nèi)容function genNode (node, state) {if (node.type === 1) {// 如果子元素還是元素會(huì)遞歸的處理return genElement(node, state)} else if (node.type === 3 && node.isComment) {// return genComment(node)} else {// 生成文本return genText(node)}}function genText (text) {return ("_v(" + (text.type === 2? text.expression // no need for () because already wrapped in _s(): JSON.stringify(text.text)) + ")")}
最后執(zhí)行我們的代碼,驗(yàn)證是否會(huì)成功:
template: '<div><span>11</span></div>'render: "with(this){return _c('div',[_c('span',[_v(11)])])}"
評(píng)論
圖片
表情
