模版编译简介
模版编译的主要目的是将模版template 转换为 渲染函数 render。
编译模版时
-
首先会调用模版编译的入口函数
compileToFunctions(template, ...)
,其内部先尝试从缓存中加载编译好的render函数,如果缓存中没有,则调用compile(template, options)
开始编译; -
在
compile(template, options)
中,首先合并options
选项,然后调用baseCompile(template.trim(), finalOptions)编译模版。这一步的核心是合并编译的options。把模版和合并后的选项传递给baseCompile()。 -
baseCompile(template.trim(), finalOptions)里完成了模版编译核心的三件事情:
- 首先调用
parse()
:把template 转换成AST 抽象语法树对象。 - 然后调用
optimize()
:对抽象语法树AST进行优化。- 标记AST Tree中的静态 sub trees;
- 检测到静态子树,设置为静态,不需要在每次重新渲染的时候重新生成节点;
- patch阶段跳过静态子树。
- 最后,调用generate(),把优化过的AST对象转换成字符串形式的代码,即AST tree生成js的创建代码
- 首先调用
-
当上面的
compile
函数执行完毕之后,会回到compileToFunctions(templates,...)
函数中:- 继续调用
createFunction()
把上一步生成的字符串形式js代码转换成函数; - render和staticRenderFns初始化完毕,挂载到Vue实例的options对应的属性中。
- 继续调用
到此模版编译的过程就结束了,模版编译过程中会标记静态根节点,会对静态根节点进行优化处理,重新渲染的时候不需要再处理静态根节点。因为静态根节点的内容不会发生改变。例外值得注意的是不要在模版当中书写过多的无意义的空白和换行,否则生成的AST对象会保留这些空白和换行,会被存储到内存中,而这些空白和换行对浏览器渲染来说是没有任何意义的,代码编写规范中也有相应的约定。
模版编译的作用
- Vue2.x 使用VNode描述视图以及各种交互,用户自己编写VNode比较复杂
- 用户只需要编写类似HTML的代码 - vue.js模版,通过编译器将模版转换为 返回VNode 的 render函数
- .vue 文件会被webpack 在构建的过程中转换成 render函数 (webpack + vue-loader)
模版编译结果体验
// console.log(vm.$options.render)
(function anonymous(
) {
with (this) {
return _c('div',
{
attrs: { "id": "app" }
},
[
_v("Hello World\n "),
_c('h1',
{ ref: "h1" },
[_v(_s(msg) + " from template")]),
_v(" "),
_c('h2', [_v(_s(user.fullname))])
])
}
})
函数定义:
- _