Vue源码解析之Template转化为AST的实现方法
在Vue的编译过程中,将模板字符串转换为AST(抽象语法树)是至关重要的一步。本文将介绍Vue源码中关于Template转化为AST的实现方法。
Template转化为AST的流程
Vue中的模板转化为AST的流程主要包括以下几个步骤:
- 解析(parse)模板字符串,生成token数组
- 将token数组转化为AST
解析模板字符串
解析模板字符串的过程,核心是正则表达式,主要是针对html标签的匹配。具体实现方法可以看下面的代码示例:
function parseHTML(html, options) {
while (html) {
let textEnd = html.indexOf('<')
if (textEnd === 0) {
const endTag = html.match(endTagRE)
if (endTag) {
advance(endTag[0].length)
continue
}
}
let text, rest, next
if (textEnd >= 0) {
rest = html.slice(textEnd)
while (
!endTagRE.test(rest) &&
!startTagOpenRE.test(rest) &&
!commentRE.test(rest)
) {
next = rest.indexOf('<', 1)
if (next < 0) break
textEnd += next
rest = html.slice(textEnd)
}
text = html.substring(0, textEnd)
}
// ...more parsing code
}
}
parseHTML函数输入的参数,就是我们要转化为AST的模板字符串,这里的实现方法中,首先判断字符串是否以"\<"开始,如果不是则认为是普通文本,直接截取并保存下来;如果是则表示匹配到了标签,这时候我们会进一步判断是否是结束标签,如果是的话则直接跳过;否则就是正常的开始标签,我们会进行标签解析。
将token数组转化为AST
经过第一步处理后,我们得到了一个token数组,接下来就可以通过此数组构建AST了。Vue的AST是通过使用 acorn 实现的,这是一个轻量级的 JavaScript 解析器,可以把JavaScript代码转化为抽象语法树(AST)。
Vue的AST结构和一般的AST结构有点不同,因为它包含了许多模板语法相关的节点,如v-if、v-for、v-on等等特殊节点。下面是一个AST的示例:
{
type: 1, // AST节点的类型,标签类型为1
tag: 'div', // 标签名称
plain: true, // 普通标签,非组件标签
static: false, // 是否为静态节点
...
children: [
// 子节点为数组
{
type: 2, // AST节点的类型,属性类型为2
name: 'v-if', // 属性名称
value: 'isShow' // 属性值
},
{
type: 3, // AST节点类型,文本节点类型为3
text: 'hello world' // 文本节点的文本内容
}
]
}
示例演示
下面是一个简单的模板字符串,我们将会对其进行解析,得到AST:
<div>
<h1 v-if="isShow">{{ title }}</h1>
<p class="desc" v-for="(item, index) in list" :key="item.id" @click="handleClick">{{ item.name }}</p>
</div>
将上述模板字符串传入parseHTML函数进行解析,得到token数组:
[
{ type: 3, text: '\n ' },
{ type: 1, tag: 'div', attrsList: [], attrsMap: {}, start: 0, end: 5, unarySlash: false, children: [] },
{ type: 3, text: '\n ' },
{ type: 1,
tag: 'h1',
attrsList: [{ name: 'v-if', value: 'isShow' }],
attrsMap: { v-if: 'isShow' },
start: 7,
end: 29,
unarySlash: false,
children: [ { type: 2, name: 'title', value: '_s(title)', dynamic: true, start: 20, end: 26, loc: [Object] } ]
},
{ type: 3, text: '\n ' },
{ type: 1,
tag: 'p',
attrsList:
[ { name: 'class', value: 'desc' },
{ name: 'v-for', value: '(item, index) in list' },
{ name: ':key', value: 'item.id' },
{ name: '@click', value: 'handleClick' } ],
attrsMap:
{ class: 'desc',
'v-for': '(item, index) in list',
':key': 'item.id',
'@click': 'handleClick' },
start: 31,
end: 89,
unarySlash: false,
children: [ { type: 3, text: ' {{ item.name }}' } ]
},
{ type: 3, text: '\n' }
]
将上述token数组传入parse函数中,得到AST:
{
type: 1,
tag: 'div',
attrsList: [],
attrsMap: {},
rawAttrsMap: {},
parent: undefined,
children: [
{
type: 3,
text: '\n '
},
{
type: 1,
tag: 'h1',
attrsList: [
{
name: 'v-if',
value: 'isShow'
}
],
attrsMap: {
'v-if': 'isShow'
},
rawAttrsMap: {},
parent: [Circular],
children: [
{
type: 2,
expression: '_s(title)',
tokens: [
{
'@binding': 'title'
}
],
text: '{{ title }}'
}
],
plain: false,
static: false,
staticRoot: false,
hasBindings: true,
key: undefined,
scopedSlots: {},
slotTarget: undefined,
slotTargetDynamic: undefined,
slotScope: undefined,
attrs: []
},
{
type: 3,
text: '\n '
},
{
type: 1,
tag: 'p',
attrsList: [
{
name: 'class',
value: 'desc'
},
{
name: 'v-for',
value: '(item, index) in list'
},
{
name: ':key',
value: 'item.id'
},
{
name: '@click',
value: 'handleClick'
}
],
attrsMap: {
'class': 'desc',
'v-for': '(item, index) in list',
':key': 'item.id',
'@click': 'handleClick'
},
rawAttrsMap: {},
parent: [Circular],
children: [
{
type: 3,
text: ' {{ item.name }}'
}
],
plain: false,
static: false,
staticRoot: false,
hasBindings: true,
key: undefined,
scopedSlots: {},
slotTarget: undefined,
slotTargetDynamic: undefined,
slotScope: undefined,
attrs: [],
computedName: undefined
},
{
type: 3,
text: '\n'
}
],
plain: false,
static: false,
staticRoot: false,
hasBindings: false,
key: undefined,
scopedSlots: {},
slotTarget: undefined,
slotTargetDynamic: undefined,
slotScope: undefined,
attrs: []
}
以上就是Vue源码解析之Template转化为AST的实现方法的详细说明,其中包含了针对模板字符串的解析方法和将token转化为具有AST结构的方法,我们通过示例演示模板字符串的解析和AST的转化过程,希望对大家有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Vue源码解析之Template转化为AST的实现方法 - Python技术站