这是我参与更文挑战的第8天,活动详情查看: 更文挑战。
前言
大多数同学在使用 Vue.js 开发时,基本都还是使用的模板。
但是 Vue.js 中创建 html 并不是只有模板这一种途径,我们可以使用 render(渲染函数)来创建 html,或者使用 jsx 来创建 html。
我们经常使用的模板会被编译转换成渲染函数,渲染函数执行后,会得到一个虚拟节点树用于渲染。
下面,我们将一起学习模板转换成渲染函数的整体过程。
模板编译
将模板编译成渲染函数可以分为两个步骤,先将模板解析成 AST(Abstract Syntax Tree,抽象语法树),然后再使用 AST 生成渲染函数。
由于静态节点时不需要重新渲染的,所以在生成 AST后,还需要遍历一遍,给所有静态节点做一个标记。
模板编译分成三部分内容:
- 将模板解析为 AST
- 遍历 AST 标记静态节点
- 使用 AST 生成渲染函数 这三部分,分别对应三个模块
- 解析器
- 优化器
- 代码生成器
graph LR
t[模板]
subgraph 模板编译
a[解析器] --> b[优化器] --> c[代码生成器]
end
r[渲染函数]
t --> a
c --> r
解析器
在解析器内部,又分了很多小解析器,包括过滤器解析器
、文本解析器
和 html 解析器
。
在使用模板时,我们可以在其中使用过滤器,而过滤器解析器的作用就是用来解析过滤器的。
文本解析器就是用来解析文本的,它的主要作用是用来解析带变量的文本,例如下面:
Hello {{name}}
不带变量的文本是一段纯文本,不需要使用文本解析器来解析。
最后也是最重要的是HTML解析器,它是解析器中最核心的模块,它的作用就是解析模板,每当解析到HTML标签的开始位置、结束位置、文本或者注释时,都会触发钩子函数,然后将相关信息通过参数传递出来,然后生成不同的 AST 节点。
AST 和 vnode 有点类似,都是使用 JavaScript 中的对象来表示节点。
优化器
优化器的目标是遍历 AST,检测出所有静态子树(永远都不会发生变化的 DOM 节点)并给其 打标记。
当 AST 中的静态子树被打上标记后,每次重新渲染时,就不需要为打上标记的静态节点创建新的虚拟节点,而是直接克隆已存在的虚拟节点。在虚拟 DOM 的更新操作中,如果发现两个节点是同一个节点,正常情况下会对这两个节点进行更新,但是如果这两个节点是静态节点,则可以直接跳过更新节点的流程。
代码生成器
代码生成器是模板编译的最后一步,它的作用是将AST转换成渲染函数中的内容,这个内容可以称为 “代码字符串”。
<p align="center" @click="a">hello world</p>
生成的代码字符串是:
with(this) {
return _c( // $createElement
'p',
{
attrs: {
align: "center"
},
on: {
click: a
}
},
[_v("hello world")]
)
}
这样一个代码字符串最终导出到外界使用时,会使用 new Function(...)
来创建函数,这个函数就叫作渲染函数。
总结
本文,我们简单了解了模板编译的流程。
模板编译需要经过三个过程:
- 将模板解析成 AST
- 遍历 AST 标记静态节点
- 使用 AST 生成代码字符串
后面,我们会详细学习解析器是如果工作的,也就是第一个过程,如果把字符串模板解析成 AST。