本文默认读者明确的了解template、el、render
选项之间的关系与区别
当我们新建一个Vue实例时,Vue内部会自动的将template
模板的内容转换为字符串传递给传递给compiler(...)
(compiler/index.js的第54行) 进而传递给baseCompiler(...)
(compiler/index.js的第10行) 进行解析,解析的结果是得到一棵AST以及render函数
在baseCompiler(...)
内部,Vue使用parse(...)
(compiler/parse/index.js的第15行) 方法来解析模板得到AST,查看其源代码,我们会发现parse(...)
的解析过程其实是通过正则匹配完成的
由于AST只是一个抽象的结构,所以需要额外的函数将其转化为可执行的js代码,这个方法就是generate(...)
(compiler/codegen/index.js的第23行),在这个方法里,Vue做了大量的工作,将AST转化为带有各种指令对应方法的字符串形式的js代码,即字符串形式的render
函数,举个例子:
<div class="main" :class="bindClass">
<div>{{text}}</div>
<div>hello world</div>
<div v-for="(item, index) in arr">
<p>{{item.name}}</p>
<p>{{item.value}}</p>
<p>{{index}}</p>
<p>---</p>
</div>
<div v-if="text">
{{text}}
</div>
<div v-else></div>
</div>
上面的代码转化为AST
AST转化为字符串形式的render
with(this){
return _c( 'div',
{
/*static class*/
staticClass:"main",
/*bind class*/
class:bindClass
},
[
_c( 'div', [_v(_s(text))]),
_c('div',[_v("hello world")]),
/*这是一个v-for循环*/
_l(
(arr),
function(item,index){
return _c( 'div',
[_c('p',[_v(_s(item.name))]),
_c('p',[_v(_s(item.value))]),
_c('p',[_v(_s(index))]),
_c('p',[_v("---")])]
)
}
),
/*这是v-if*/
(text)?_c('div',[_v(_s(text))]):_c('div',[_v("no text")])],
2
)
}
可以看到,最终生成的代码带有很多的_c、_l、_s、_v
方法,在core/instance/render.js的117行,可以发现这是对应各种Vue指令的函数方法,用于辅助处理各种Vue指令,通过这些函数,render函数最后会返回一个VNode节点,在_update的时候,经过patch与之前的VNode节点进行比较,得出差异后将这些差异渲染到真实的DOM上。