本文基于vue-2.4.4源码进行分析
模板编译是Vue 2.0中很重要的一个环节,它将template
编译成render
函数,最后生成Virtual DOM
渲染在页面。
本篇文章将结合源码对模板编译流程进行分析:
从源码角度看,模板编译主要经历如下流程:
vue-compile.png即:
首先,在项目初始化时挂载DOM节点
并获取template
然后将 template
编译成 render 函数
。这个编译过程包含:
1. check 缓存,如果有缓存数据就读取缓存数据
2. 获取并合并options
3. parse: 将template解析成AST
4. optimize: 标记静态节点
5. generate: 拼接 render function 字符串
6. 通过 new function 生成渲染函数
7. 缓存
其中,3、4、5是整个模板编译的核心。
baseCompile函数(src/compiler/index.js)依次执行parse
,optimize
,和generate
,最后返回一个包含ast
、render
和staticRenderFns
的对象。
export const createCompiler = createCompilerCreator(function baseCompile (
template: string,
options: CompilerOptions
): CompiledResult {
// 3. parse: 将template解析成AST
const ast = parse(template.trim(), options)
// 4. optimize: 标记静态节点
optimize(ast, options)
// 5. generate: 拼接 render function 字符串
const code = generate(ast, options)
return {
ast,
render: code.render,
staticRenderFns: code.staticRenderFns
}
})
parse: 将template解析成AST
这里,先简单介绍下AST。
AST全称是:Abstract Syntax Tree (抽象语法树),是源代码语法所对应的树状结构。Vue 2.0中ASTNode有三种形式:ASTElement
、ASTText
、ASTExpression
。
Vue 2.0中的parse函数(src/compiler/parser/index.js)采用了jQuery作者John Resig的HTML Parser
parseHTML(template, {
start (tag, attrs, unary) {
// 解析到新的节点时调用,包括节点tagName, attributes等信息
},
end () {
// 节点解析结束时调用,包括节点tagName等信息
},
chars (text: string) {
// 文本解析完成时调用,包括文本本身
}
}
如:<div id='app'>{{ message }}</div>
parseHTML
后的结果是:
optimize: 标记静态节点
optimize函数(src/compiler/optimizer.js)会对静态节点打标,提取最大的静态树,在后面patch时,被标记为static的节点将直接跳过diff。
export function optimize (root: ?ASTElement, options: CompilerOptions) {
if (!root) return
isStaticKey = genStaticKeysCached(options.staticKeys || '')
isPlatformReservedTag = options.isReservedTag || no
// first pass: mark all non-static nodes.
markStatic(root)
// second pass: mark static roots.
markStaticRoots(root, false)
}
generate: 拼接 render function 字符串
generate函数(src/compiler/codegen/index.js)
export function generate (
ast: ASTElement | void,
options: CompilerOptions
): CodegenResult {
const state = new CodegenState(options)
const code = ast ? genElement(ast, state) : '_c("div")'
return {
render: `with(this){return ${code}}`,
staticRenderFns: state.staticRenderFns
}
}
总结
模板编译的核心:template
→ AST
→ render function
网友评论