十行代码实现的一个js模板引擎

心血来潮,来写一个模板引擎吧!

功能就不多说了

实现思路

从最简单的开始吧

假设一个模板长这样

<h1><% var world = 'world!'; %> hello <%= world %></h1>

模板转化后应该到这样的:

    // 假设输出的结果存放在变量p中
    p += '<h1>';
    var world = 'world!';
    p += ' hello ';
    p += world;
    p += '</h1>';

总结一下这个过程,其实就只有三条规则:

  1. %>...<% 转换为 %>p += '...';<%, 起始和结束同此, 将内容直接作为输出
  2. <%...%> 转换为 ...;, 逻辑处理, 直接执行
  3. <%=...%> 转换为 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仓库