心血来潮,来写一个模板引擎吧!
功能就不多说了
实现思路
从最简单的开始吧
假设一个模板长这样
<h1><% var world = 'world!'; %> hello <%= world %></h1>
模板转化后应该到这样的:
// 假设输出的结果存放在变量p中
p += '<h1>';
var world = 'world!';
p += ' hello ';
p += world;
p += '</h1>';
总结一下这个过程,其实就只有三条规则:
%>...<%转换为%>p += '...';<%, 起始和结束同此, 将内容直接作为输出<%...%>转换为...;, 逻辑处理, 直接执行<%=...%>转换为p += (...);, 将运算结果作为输出
实现
实现就很简单了把上面的规则写成代码,
tpl.replace(/(\s)+/g, " ") // 主要是为了处理换行
.replace(/(\%\>|^)(.+?)(\<\%|$)/g, "$1p += '$2';$3")
.replace(/\<\%([^=](.(?!\<\%))+)\%\>/g, "$1;")
.replace(/\<\%\=((.(?!\<\%))+)\%\>/g, "p += ($1);")
然后包装一下
function render (tpl) {
return new Function("data", "var p = ''; with(data){" +
tpl.replace(/(\s)+/g, " ")
.replace(/(\%\>|^)(.+?)(\<\%|$)/g, "$1p += '$2';$3")
.replace(/\<\%([^=](.(?!\<\%))+)\%\>/g, "$1;")
.replace(/\<\%\=((.(?!\<\%))+)\%\>/g, "p += ($1);") +
"} return p; ");
}
完成!
测试
// 模板
var tpl = `<ul>
<% for (var i = 0; i < list.length; i++) { %>
<li><%= list[i] %></li>
<% } %>
</ul>`;
var renderFn = render(tpl); // 获取渲染函数
var renderResult = renderFn({list:["a", "b", "c", "d"]}); // 渲染结果
// <ul> <li>a</li> <li>b</li> <li>c</li> <li>d</li> </ul>
大功告成
当然中间还是遇到了很多问题,不过最终的结果还是非常好的,这个轮子项目已经放在github仓库