模板:写在标签中的类似于原生HTML的内容
模板编译是用模板生成一个render函数
render函数就可以生成与模板对应的VNode,之后再进行patch算法,最后完成视图渲染。
分三个阶段:
功能 | 类 | 源码路径 | |
---|---|---|---|
模板解析 | 将一堆模板字符串用正则等方式解析成抽象语法树AST | 解析器 | src/compiler/parser/index.js |
优化 | 遍历AST,找出其中的静态节点,并打上标记 | 优化器 | src/compiler/optimizer.js |
代码生成 | 将AST转换成渲染函数 | 代码生成器 | src/compiler/codegen/index.js |
模板解析
在模板内,除了有常规的HTML标签外,还有一些文本信息以及在文本信息中包含过滤器。
不同的内容需要不同的解析规则,对应不同解析器。常规HTML的parseHTML,文本parseText、过滤器解析器parseFilters(解析文本中如果包含过滤器)。
HTML解析器是主线,先用HTML解析器进行解析整个模板,在解析过程中如果碰到文本内容,那就调用文本解析器来解析文本,如果碰到文本中包含过滤器那就调用过滤器解析器来解析。
总之:一边解析不同的内容一边调用对应的钩子函数生成对应的AST节点,最终完成将整个模板字符串转化成AST。解析器内维护了一个栈,用来保证构建的AST节点层级与真正DOM层级一致。
parseHTML
// 代码位置:/src/complier/parser/index.js
/**
* Convert HTML string to AST.
* 将HTML模板字符串转化为AST
*/
export function parse(template, options) {
// ...
parseHTML(template, {
warn,
expectHTML: options.expectHTML,
isUnaryTag: options.isUnaryTag,
canBeLeftOpenTag: options.canBeLeftOpenTag,
shouldDecodeNewlines: options.shouldDecodeNewlines,
shouldDecodeNewlinesForHref: options.shouldDecodeNewlinesForHref,
shouldKeepComment: options.comments,
// 当解析到开始标签时,调用该函数
start (tag, attrs, unary) {
//生成元素类型的AST节点
},
// 当解析到结束标签时,调用该函数
end () {
},
// 当解析到文本时,调用该函数
chars (text) {
//生成文本类型的AST节点
},
// 当解析到注释时,调用该函数
comment (text) {
//生成评论类型的AST节点
}
})
return root
}
调用parseHTML函数时为其传入的两个参数分别是:
template:待转换的模板字符串;
options:转换时所需的选项,提供了一些解析HTML模板时的一些参数,同时还把这4个钩子函数作为参数传给解析器parseHTML,当解析器解析出不同的内容时调用不同的钩子函数从而生成不同的AST。
例如start
// 当解析到标签的开始位置时,触发start
start (tag, attrs, unary) {
let element = createASTElement(tag, attrs, currentParent)
}