Vue学习笔记 — 模板编译原理
Vue.js提供了模板语法,允许我们声明式地描述状态和DOM之间地绑定关系,然后通过模板来生成真实DOM并将其呈现在用户界面上
一、渲染步骤
将模板编译成渲染函数可以分为两个步骤,先将模板解析成AST(Abstract Syntax Tree,抽象语法树),然后再使用AST生成渲染函数
由于静态节点不需要总是重新渲染,因此在生成AST之后与生成渲染函数之前会需要一个操作->遍历一遍AST,给所有静态节点做一个标记,这样在虚拟DOM更新节点时就会发现这个标记,也就不会重新渲染它
模板编译答题分为三个部分:
- 将模板解析为AST
- 遍历AST标记静态节点
- 使用AST生成渲染函数
这三个部分在模板编译中分别抽象出三个模块来实现功能:
- 解析器
- 优化器
- 代码生成器
二、解析器
解析器地功能就是将模板解析为AST
在解析器内部,分成了很多小的解析器->过滤器解析器,文本解析器、HTML解析器,通过主线将这些解析器组装在一起
文本解析器主要用于解析带有变量的文本Hello{
{name}}
,不带有变量的文本是不需要使用文本解析器进行解析的
解析器的内部其实页分为了好几种解析器,有HTML解析器、文本解析器、以及过滤器解析器等其中最重要的就是HTML解析器,它在解析HTML的过程中会触发各种钩子函数,其中包括有开始标签钩子函数、结束标签钩子函数、文本钩子函数以及注释钩子函数
以下是相关的伪代码:
parseHTML(template, {
start(tag, attrs, unary) {
//标签名, 标签的属性, 是否是自闭合函数
// 每当解析到标签开始位置时,触发该函数
},
end() {
// 每当解析到标签结束位置时,触发该函数
},
chars(text) {
// 每当解析到文本时,触发该函数
},
comment(text) {
// 每当解析到注释时,触发该函数
}
})
当HTML解析器进行解析时会依次触发这些钩子函数,注意:哪怕是仅含有空格,也会触发start钩子函数
在parseHTML()函数中会循环对模板进行解析,每一轮循环中,都会进行字符串的截取,被截取的片段会分很多类型:
开始标签、结束标签、HTML注释、DOCTYPE,条件注释、文本
截取开始标签
在HTML解析器中,想分辨模板是否以开始标签开头不难,应该先判断是否以 < 开头, 如果不是,那么它一定不是以开始标签开头的模板,也就不需要执行开始标签的截取操作, 如果是以 < 开头的,那么就需要对其具体的标签类型进行解析判断,这也就需要开始使用正则表达式进行解析了
const ncname = `[a-zA-z_][\\w\\-\\.]*`
const qnameCapture = `((?:${
ncname}\\:)?${
ncname})`
const startTagOpen = new RegExp(`^<${
qnameCapture}`)
对开始标签进行截取后,会通过正则表达式进行分析,开始标签的解析中需要判断是否为自闭合标签,例如<