在用vue开发项目的过程中,生命周期里有mounted这一环节,mounted方法是把template会被编译成AST语法树。说AST之前,要说一说编译器,编译器的作用是把源代码编译成目标代码,源代码是什么呢? 用vue开发的话,源代码就是.vue文件,目标代码就是可被浏览器执行的.js文件。编译器的概念很多,大致上分为词法分析、语法分析(句法分析)、类型检查/推导,代码优化,代码生成...等等,编译器是大学要学的一门课。如果只讲编译器是很枯燥的,大部分人看了一部分后就看不下去了,通过vue代码能够直观的理解编译器的工作方式,vue的编译器和大部分编译器一样,大致也分为三个阶段,即:词法分析 -> 句法分析 -> 代码生成。
在词法分析阶段vue会把字符串模板解析成一个个的令牌(token),该令牌将用于句法分析阶段,在句法分析阶段会根据令牌生成一棵AST,最后再根据该 AST生成最终的渲染函数,这样就完成了代码的生成。vue模板的解析基本分两步:
1、在mounted阶段,执行compile方法将template里的内容转化成html。
2、compile过程分三步:parse,optimize,generate。
今天先分析一下compile方法是如何来解析template模板的,也就是compile的parse阶段。
compile 的作用是解析模板,生成渲染模板的 render:
比如说这样的模板:
<div>
<span></span>
</div>
经过compile之后,编译成render函数
_c('div', [_c('span')])
而render的作用是生成如下的模板节点:
{
tag: "div",
children:[{
tag: "span",
text: undefined
}]
}
parse基础解读
对模板进行解析,生成AST,意思就是通过json键值对形式,把template用树这样的数据结构表示出来。
比如上面的例子:
<div>
<span class="list"></span>
</div>
生成的 AST 是这样,所有模板中出现的数据,你都可以在 AST 中找到
{
tag: "div",
children:[{
tag: "span",
children: [],
attrsMap: {class: "list"}
}]
}
AST就是用数据的方式来描述事物。
parse详细分析
parse 是 渲染三巨头的老大,其作用是把 template 字符串模板,转换成 AST,关于AST的概念,我也查了很多资料,主要是以树状结构描述语法结构,什么意思呢?
比如:
<div>
<span>123</span>
</div>
这是一个带有表达式的模板,转化起来相当简单。
AST={
tag:'div',
type: 1,
children:[{
tag: 'span',
type: 1,
children:[{
type:3,
text: '123'
}]
}]
}
这个很简单吧,type是描述节点的类型,它有三个可取值,分别是 1、2、3,分别代表的含义是:
1:代表当前节点类型为标签,例如:div、span、li
2:包含字面量表达式的文本节点,例如: {{info}}
3:普通文本节点或注释节点,例如:"周笔畅是男的"
parse源码分析
function parse(template) {
var stack = []; // 缓存模板中解析的每个节点的 ast
var root; // 根节点,是 ast
var currentParent; // 当前解析的标签的父节点
/**
* parseHTML 处理 template 匹配标签,再传入 start,end,chars 等方法
**/
parseHTML(template, {
start: (..被抽出,在后面)
end: (..被抽出,在后面), // 为 起始标签 开启闭合节点
chars: (..被抽出,在后面) // 文字节点
});
return root
}