美文网首页
模板引擎的简单实现

模板引擎的简单实现

作者: 罗超伟 | 来源:发表于2018-07-31 10:16 被阅读10次

在实现一套基本的模板引擎前我先介绍一下可能用到的一些东西

  • String.prototype.replace
  • 正则匹配与子匹配
  • 方法的另一种定义方式

String.prototype.replace

这个字符串的替换方法,本身有几个重载(当然在js中本身没有重载,只是对参数做了一些特殊的处理),今天我只想介绍一下这种:

var str = "{zhzello} {zworldz},{zhelloz} zhangsanz";
var reg = /{([\s\S].)?}/g;
// 其中callback会根据匹配的内容传入不同参数,每一次匹配都会调用
// -无子匹配时接收三个参数:匹配项目、匹配索引、原字符串
// -有子匹配时接收4个参数:匹配项目、子匹配项目、匹配索引、原字符串
// 返回一个新串替换原串中的匹配项目
str.replace(reg,callback);

正则匹配与子匹配

我了解的也不多,具体参考一下另一篇

方法的另一种定义方式

function doSth(){
  console.log('I can do something!');
}
var doSth2 = new Function('console.log(\'I can do something!\');');

上面的两种方法的定义效果是一样的,只是平时不推荐使用new Function,但其实通过function定义的方法最后还是会转成new Function的形式(请允许我做一个XX的表情)。

模板引擎的实现

首先看一下代码

 * <ul>
 * <%for(var i =0;i<list.length;i++){%>
 *  <li>
 *    <%= list[i] %>
 *  </li>
 * <%}%>
 * </ul>
 * <%}%>
 */

let str = 'var tmp = \'\';';
str += 'tmp += \'<br />\';';
str += 'if(list&&list.length){';
str += 'tmp += \'<ul>\'';
str += 'for(var i =0;i<list.length;i++){';
str += 'tmp += \'<li>\'';
str += 'tmp += list[i]';
str += 'tmp += \'</li>\'';
str += '}';
str += 'tmp += \'</ul>\'';

模板的解析主要就是一个动态js调用与字符串的拼接过程,我将之分成下面几步:
1、找到表达式的开始位置;
2、拼接表达式之前的字符串;
3、判断表达式是赋值还是其它表达式,赋值时求值拼接,否则保留表达式;
4、找到下一个表达式的位置;
5、找到表达式与上一次表达式之前的字符串拼接;



N、将最后的字符串加入
N+1、将上面的表达式通过new Function构造成一个函数并调用就可得到编译后的文本
具体参照代码

function buildFunc(tpl){
    let index = 0;
    let reg = /<%([\s\S]+?)%>/g;
    //out 为编译后的方法体
    let body = 'var out=\'\';';
    body += '';
    tpl.replace(reg,(match,val,offset)=>{
      body += 'out += \''+ tpl.substring(index,offset) +'\';';
      if(match.includes('<%=')){
        //如果是取值将输出的字符串加上取值表达式即可
        body += 'out += '+val.substr(1)+';';
      }else{
        //不是取值就将表达式拼到方法体就即可
        body += val;
      }
      index =offset+match.length;//设置代码后面的位置
    });

    //将最后的字符串加入
    body += tpl.substring(index);
    body += 'return out;'
    return body;
  }
var tpl ='';//模板字符串
var func = new Function(buildFunc(tpl));
func()// 输出编译后的文本

在不引用外部变量的情况下,现在已经基本可以成功,但对于我们前面给到的模板

var tpl ='<br />\
 <% if(list&&list.length){ %>\
 <ul>\
 <%for(var i =0;i<list.length;i++){%>\
  <li>\
    <%= list[i] %>\
  </li>\
 <%}%>\
 </ul>\
 <%}%>';
var list= ['Hello','World','你好','世界'];
var func = new Function(buildFunc(tpl));
func()// list is not defined

会报出list is not defined的错误,因为使用Function构造器生成的函数,并不会在创建它们的上下文中创建闭包;它们一般在全局作用域中被创建。当运行这些函数的时候,它们只能访问自己的本地变量和全局变量,不能访问Function构造器被调用生成的上下文的作用域。这和使用带有函数表达式代码的eval不同。
那我们怎么将list弄到动态方法的作用域中去呢?使用with将动态方法的方法体用with块包起来就可以了

var funcBody = buildFunc(tpl);
funcBody = 'with(Data){'+funcBody+'}';
var func = new Function('Data',funcBody);
func({list:list})// 输出正确的

本文代码

相关文章

  • 模板引擎的简单实现

    在实现一套基本的模板引擎前我先介绍一下可能用到的一些东西 String.prototype.replace 正则匹...

  • 500 lines or less学习笔记(十六)——模板引擎(

    模板引擎在 Web 前端开发的时候经常用到,本文介绍了其原理本利用200多行代码实现了一个简单的模板引擎。 原文作...

  • Node.js 动手实现简单的模板引擎

    根据数据和模板动态渲染页面(实现一个简单的模板引擎) 准备HTML模板文件index.html 创建服务器serv...

  • 课程管理系统

    使用node实现简单的增删改查 一.handlebars模板引擎的使用 handlebars的安装 handleb...

  • Enjoy模板引擎原理

    模板引擎是web开发中必不可少的部分,Enjoy模板引擎做为JFinal的默认模板引擎,也可以单独使用。它的实现非...

  • 基于 POI 实现一个 Excel 模板引擎

    0. 效果预览 新建一个 excel 文档template.xlsx,作为模板: 实现这是一个简单的置换型模板引擎...

  • 使用Poi-tl实现的文档导出

    World模板引擎[http://deepoove.com/poi-tl/] 项目利用这个模板引擎实现了超级复杂的...

  • JS代码题4

    实现一个简单的模板引擎 实现render函数: 这道题的主要考察正则的有关知识: 圆括号 test()方法 exe...

  • Laravel 文档阅读:Blade 模板

    简介 Blade 是 Laravel 提供的模板引擎,它简单强大。不像其他的 PHP 模板引擎,Blade 允许在...

  • Laravel(四)

    Blade模板引擎简介 Blade是Laravel提供的一个既简单又强大的模板引擎和其它流行的PHP模板引擎不一样...

网友评论

      本文标题:模板引擎的简单实现

      本文链接:https://www.haomeiwen.com/subject/ognxvftx.html