最近有个朋友问<%=...%>
和 {{ Mustache }}
插值语法的一些问题,突然想起以前使用<%=...%>
语法进行模板编译的日子,似乎已经很久远了,刚好有点时间所以写篇文章重新温故下模板编译的处理逻辑。
关键 正则表达式
、eval函数
和字符串拼接
1 2 3 4 5
| <ul> <% for(var i = 0; i< data.list.length;i++) {%> <li><%= data.list[i] %></li> <% } %> </ul>
|
给定上面的模板字符串,我们希望能够提供一个模板编译函数,传递数据(data:["a","b","c"])
给该函数以编译出下面的文本标签。
1 2 3 4 5
| <ul> <li>a</li> <li>b</li> <li>c</li> </ul>
|
思路 对于上面的字符串模板,如果要编译得到目标字符串,那么关键点在于for循环的处理,这里最简单的办法就是直接通过eval函数
来执行 for循环
部分的代码,而<% 和 %>
等部分则需要通过正则来进行替换。假设,我们在这里提供一个 echo函数
用于做字符串的拼接,那么可以考虑先把模板字符串处理为下面的样式,再行处理。
1 2 3 4 5 6 7
| echo('<ul>'); for(var i = 0; i< data.list.length;i++) { echo('<li>'); echo(data.list[i]); echo('</li>'); } echo('</ul>');
|
具体实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
|
let template = ` <ul> <% for(var i = 0; i< data.list.length;i++) {%> <li><%= data.list[i] %></li> <% } %> </ul> `
function compile(template) {
let expr = /<%([\s\S]+?)%>/g; let evalExpr = /<%=(.+?)%>/g;
template = template .replace(evalExpr, '`); \n echo($1); \n echo(`') .replace(expr, '`); \n $1 \n echo(`');
template = 'echo(`' + template + '`)';
let script = `(function parse(data){ let output = ""; function echo(html){ output += html.trimEnd(); } ${template} return output; })`; console.log('script', script);
return script; }
let parse = eval(compile(template));
let html = parse({ list: ["a", "b", "c"] }); console.log(html);
|