这篇文章主要简单介绍 template 转换成 ast 的过程,也就是 vue 中 parse 的过程。
假设 template 模版为
const template = `<div>
<div style='color: red'>{{count}}</div>
<button @click="addCount">addCount</button>
</div>`
首先要了解一下 html parser,vue 中的 parseHTML 是从 simplehtmlparser 修改来的,simplehtmlparser 代码链接:http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
parseHTML 过程其实就是从前向后的字符串匹配过程。html parser 的主要思想如下,从前向后匹配出 html 标签名称、属性、文本节点内容、注释等等,触发对应的回调函数,其中 s 是输入的字符串模版,contentHandler 是匹配到内容后执行的回调函数。
function parseHTML(s, contentHandler) {
while (s.length > 0) {
// Comment
if (s.substring(0, 4) == "<!--") {
index = s.indexOf("-->");
if (index != -1) {
contentHandler.comment(s.substring(4, index));
s = s.substring(index + 3);
treatAsChars = false;
} else {
treatAsChars = true;
}
}
// end tag
else if (s.substring(0, 2) == "</") {
contentHandler.end(sTagName);
}
// start tag
else if (s.charAt(0) == "<") {
var attrs = parseAttributes(sTagName, sRest);
contentHandler.start(sTagName, attrs);
}
if (treatAsChars) {
index = s.indexOf("<");
if (index == -1) {
contentHandler.chars(s);
s = "";
} else {
contentHandler.chars(s.substring(0, index));
s = s.substring(index);
}
}
}
}
我们将刚才的模版输入到这个函数中
const handler = {
start: function (sTagName, oAttrs) {
console.log('start', sTagName, oAttrs)
},
end: function (sTagName) {
console.log('end', sTagName)
},
chars: function (s) {
console.log('chars', s)
},
comment: function (s) {
console.log('comment', s)
}
};
parseHTML(template, handler);
这样就可以按顺序匹配到开始标签、标签属性、元素中文本节点、结束标签。
start div []
chars
start div [ { name: 'style', value: 'color: red' } ]
chars {{count}}
end div
chars
start button [ { name: '@click', value: 'addCount' } ]
chars addCount
end button
chars
end div
最后如何生成 AST,就是一道栈相关的算法题啦,大家可以自己尝试一下。