template编译的过程可分为三个阶段:parse(将template进行正则解析得到指令、class、style等数据生成AST)、optimize(进行优化标记静态部分) 与 generate(将AST生成render function)
样例模板:
<div :class="c" class="demo" v-if="isShow">
<span v-for="item in sz">{{item}}</span>
</div>
1、首先看parse,主要是复杂的正则匹配,生成AST,如下,具体的正则解析先不看了。。。太多了
{
/* 标签属性的map,记录了标签上属性 */
'attrsMap': {
':class': 'c',
'class': 'demo',
'v-if': 'isShow'
},
/* 解析得到的:class */
'classBinding': 'c',
/* 标签属性v-if */
'if': 'isShow',
/* v-if的条件 */
'ifConditions': [
{
'exp': 'isShow'
}
],
/* 标签属性class */
'staticClass': 'demo',
/* 标签的tag */
'tag': 'div',
/* 子标签数组 */
'children': [
{
'attrsMap': {
'v-for': "item in sz"
},
/* for循环的参数 */
'alias': "item",
/* for循环的对象 */
'for': 'sz',
/* for循环是否已经被处理的标记位 */
'forProcessed': true,
'tag': 'span',
'children': [
{
/* 表达式,_s是一个转字符串的函数 */
'expression': '_s(item)',
'text': '{{item}}'
}
]
}
]
}
2、optimize
optimize 主要作用就跟它的名字一样,用作「优化」。
这个涉及到后面要讲 patch 的过程,因为 patch 的过程实际上是将 VNode 节点进行一层一层的比对,然后将「差异」更新到视图上。那么一些静态节点是不会根据数据变化而产生变化的,这些节点我们没有比对的需求,是不是可以跳过这些静态节点的比对,从而节省一些性能呢?
那么我们就需要为静态的节点做上一些「标记」,在 patch 的时候我们就可以直接跳过这些被标记的节点的比对,从而达到「优化」的目的。
经过 optimize 这层的处理,每个节点会加上 static 属性,用来标记是否是静态的。
3、generate
generate 会将 AST 转化成 render funtion 字符串,最终得到 render 的字符串以及 staticRenderFns 字符串。
大概会将AST编译成这样:
with(this){
return (isShow) ?
_c(
'div',
{
staticClass: "demo",
class: c
},
_l(
(sz),
function(item){
return _c('span',[_v(_s(item))])
}
)
)
: _e()
}
这里_c的意思就是createElement,创建一个VNode节点。执行这个render函数就会得到VNode节点。