手动实现简单的模版引擎

关键点

Function构造函数可以接收任意数量的参数,但是最后一个参数始终看成为函数体,前面的参数被看成返回的函数的参数

<body>
  <div id="box">
    My skills:
    <%if(this.showSkills) {%>
      <%for(var index in this.skills) {%>
        <a href="#">
          <%this.skills[index]%>
        </a>
        <%}%>
          <%} else {%>
            <p>none</p>
            <%}%>
  </div>
  <script>
    const box = document.getElementById('box')
    {
      const TemplateEngine = function (tpl, data) {
        let re = /<%([^%>]+)?%>/g, code = 'let r=[];\n', cursor = 0;

        var add = function (line, js) {
          // js变量不应该push时带有引号
          js ? code += `r.push(${line});\n` :
            code += `r.push("${line.replace(/"/g, `\\"`)}");\n`;// 处理后=> r.push("<p>Hello, my n\"ame is ");
        }
        while (match = re.exec(tpl)) {
          add(tpl.slice(cursor, match.index)); // 将匹配项之前的字符push进数组,即【<p>Hello, my name is 】push进去
          add(match[1], true);// 将匹配到的变量push进去, 即【this.name】
          cursor = match.index + match[0].length; // 移动截取下标
        }
        add(tpl.substr(cursor, tpl.length - cursor));// 将最后一段push进去,即【years old.</p>】
        code += `return r.join("");`; // <-- return the result
        console.log("code=>", code);
        // Function构造函数可以接收任意数量的参数,但是最后一个参数始终看成为函数体,前面的参数被看成返回的函数的参数
        return new Function(code.replace(/[\r\t\n]/g, '')).apply(data);
      }
      var template = '<p>Hello, my n"ame is <%this.name%>. I\'m <%this.profile.age%> years old.</p>';
      console.log("最终=>", TemplateEngine(template, {
        name: "Krasimir Tsonev",
        profile: { age: 29 }
      }));
    }


    // 支持关键字
    {
      const TemplateEngine = function (html, options) {
        let re = /<%([^%>]+)?%>/g, reExp = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g, code = 'var r=[];\n', cursor = 0;
        const add = function (line, js) {
          js ? (code += line.match(reExp) ? line + '\n' : `r.push(${line});\n`) :
            (code += line != '' ? `r.push("${line.replace(/"/g, `\\"`)}");\n` : '');
          return add;
        }

        while (match = re.exec(html)) {
          add(html.slice(cursor, match.index))(match[1], true);
          cursor = match.index + match[0].length;
        }

        add(html.substr(cursor, html.length - cursor));
        code += `return r.join("");`;
        return new Function(code.replace(/[\r\t\n]/g, '')).apply(options);
      }

      // var template =
      //   'My skills:' +
      //   '<%if(this.showSkills) {%>' +
      //   '<%for(var index in this.skills) {%>' +
      //   '<a href="#"><%this.skills[index]%></a>' +
      //   '<%}%>' +
      //   '<%} else {%>' +
      //   '<p>none</p>' +
      //   '<%}%>';
      // 测试
      let template = box.innerHTML.toString().replace(/&lt;/g, "<").replace(/&gt;/g, ">")
      let html = TemplateEngine(template, {
        skills: ["js", "html", "css"],
        showSkills: true
      })
      box.innerHTML = html
    }
  </script>
</body>

参考:博客1
原文地址:http://blog.jobbole.com/56689/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值