在用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
}

parse 接收 template 字符串,使用 parseHTML 这个函数在 template 中匹配标签

并传入 start,end,chars 三个函数 供 parseHTML 处理标签等内容。

这篇文章先写到这里,下一篇文章再给大家看一下parseHTML究竟是怎么回事,铺开来讲,AST是一个庞大的知识库,没有足够的知识、精力和体力是难以完成的,编写不易,请大家多多点赞。