1 // 将字符串的属性转换为key:value类型
2 const convert = (attr) => {
3 if (attr == undefined) {
4 return [];
5 } else {
6 let point = 0;
7 let flag = false;
8 let result = [];
9 for (let i = 0; i < attr.length; i++) {
10 if (attr[i] == '"') {
11 flag = !flag;
12 } else if (!flag && attr[i] == ' ') {
13 if (!/^\s*$/.test(attr.slice(point, i))) {
14 result.push(attr.slice(point, i).trim());
15 point = i;
16 }
17 }
18 }
19 result.push(attr.slice(point, attr.length).trim());
20 result = result.map((item) => {
21 let res = item.match(/^(.+)="(.+)"$/);
22 return {
23 name: res[1],
24 value: res[2]
25 }
26 })
27 return result;
28 }
29 }
30 // 将模板dom转换为对象的形式,以AST的形式实现
31 function prase(template) {
32 let startStark = [];
33 let endStark = [{ children: [] }];
34 let startReg = /^\<([a-z]+[1-6]?)(\s[^\<]+)?\>/; //开始标签的正则
35 let endReg = /^\<\/([a-z]+[1-6]?)+\>/; //结束标签的正则
36 let innerReg = /^([^\<]+)\<\/[a-z]+[1-6]?\>/;
37 let attrReg = /^\"(a-z)+\"/;
38 let i = 0;
39 let rest = template;
40 while (i < template.length - 1) {
41 rest = template.substring(i);
42 // 匹配开始标签
43 if (startReg.test(rest)) {
44 // 把开始的标签提取出来
45 let tag = rest.match(startReg)[1];
46 let attr = rest.match(startReg)[2];
47 let attrs = convert(attr);
48 let attrLen = attr != undefined ? attr.length : 0;
49 // push到startStark栈中
50 startStark.push(tag);
51 // 结束标签push一个空栈顶用来存放,内容
52 endStark.push({ tag: tag, children: [], attrs: attrs });
53 // 加2是因为<>
54 i += tag.length + 2 + attrLen;
55 // 匹配结束标签
56 } else if (endReg.test(rest)) {
57 // 把结束的标签提取出来
58 let tag = rest.match(endReg)[1];
59 // 判断是否是封闭标签,如果是,就去除栈顶
60 if (startStark[startStark.length - 1] === tag) {
61 // 去除开始标签
62 startStark.pop();
63 // 在下面检查到内容字符之后,检测到闭标签时弹栈,弹出的数组包含了内容字符
64 let pop_arr = endStark.pop();
65 // 把弹出栈的元素push给新的栈顶元素
66 endStark[endStark.length - 1].children.push(pop_arr);
67 } else {
68 new Error(startStark[startStark.length - 1] + '没有封闭');
69 }
70 // 加3是因为</>
71 i += tag.length + 3;
72 // 匹配是否是内容字符且不为空内容
73 } else if (innerReg.test(rest)) {
74 // 把文本节点的内容提取出来
75 let inner = rest.match(innerReg)[1];
76 // 判断是否为空
77 if (!/^\s+$/.test(inner)) {
78 // 栈顶的元素push进去该文本节点
79 endStark[endStark.length - 1].children.push({ text: inner, type: 3 });
80 }
81 i += inner.length;
82 }
83 else {
84 i++;
85 }
86 }
87 return endStark[0].children[0];
88 }
89 prase(`<div>
90 <h3 class="box" id="box2">你好</h3>
91 <ul>
92 <li>A</li>
93 <li>B</li>
94 <li>C</li>
95 </ul>
96 </div>`);