本节偷个懒,可以参考这里
经过前面几个步骤,AST上的维护节点的父子关系,并且每个节点上都有足够的信息。
这里根据这些信息来构造render函数,render函数的形式以demo为例
代码语言:javascript复制(function anonymous() {
with (this) {
return _c('div', {
staticClass: "container",
attrs: {
"id": "app"
}
}, [_c('slot-test', {
scopedSlots: _u([{
key: "header",
fn: function (slotProps) {
return [_c('div', [_v("name: " _s(slotProps.user.name))]), _v(" "), _c('div', [_v("sex: " _s(slotProps.user.sex))])]
}
}])
}), _v(" "), _c('div', [_v("static node")]), _v(" "), (showSpan) ? _c('span', {
class: {
active: showSpan
},
on: {
"click": clickHandler
}
}, [_v(" show Span")]) : _c('span', {
on: {
"click": clickHandler
}
}, [_v("hide Span")]), _v(" "), _l((items), function (item, index) {
return _c('div', [_c('span', [_v(" " _s(item))])])
}), _v(" "), _c('input', {
directives: [{
name: "model",
rawName: "v-model",
value: (searchText),
expression: "searchText"
}],
domProps: {
"value": (searchText)
},
on: {
"input": function ($event) {
if ($event.target.composing)
return;
searchText = $event.target.value
}
}
})], 2)
}
}
)
with中的this是vue实例,_u等等都是挂载在该Vue原型上的,_c是直接挂载vm实例上的。
代码语言:javascript复制// renderMixin -> installRenderHelpers(Vue.prototype)
// initRender -> vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)
总结
整个模板解析分为四个步骤
simple-html-parser
来遍历html字符串,找出元素标签(包括收集属性)、文本- 基于
simple-html-parser
提供的钩子start
/end
来解析收集来属性,并创建AST节点,将解析后的信息保存到每个AST节点上。并建立AST节点父子关系,root代表整个AST optimize
:不影响主流程,完全是从创建虚拟DOM和虚拟DOM的diff层面来优化这两个步骤(减少虚拟DOM的创建和diff)- 基于砂上面的AST的代码生成,并非还原为
html
,而是vue
需要的render
函数,看到关键的方法_c
对应运行时的creatElement
用来创建虚拟DOM的。
整体看逻辑还是很清晰的。