写一个简单的模板引擎
2019-06-02 14:27
537 查看
写一个简单的模板引擎
ES6 开始支持模板字符串(Template literals),支持如下的写法:
`string text ${expression} string text`;
其实在很多模板引擎中,常常会有这样需求,比如常用的 doT,使用类似的语法
<div>{{=1+2}}</div> // 或者支持循环或者判断 {{for(var i in it){}}} <span>{{=i}}</span> {{}}}
简单插值的实现
我们先来看看一个模板引擎基本的实现需要什么,先不考虑循环和判断,只支持变量运算。
打开Babel,输入
const a = 1; console.log(`Hi\n${2 + 3}!dk${a}`);
经过
Babel转义以后,可以看到
"use strict"; var a = 1; console.log("Hi\n".concat(2 + 3, "!dk").concat(a));
可以看到,
Babel把插值提取到 concat 入参,通过函数入参的自计算实现了 Template literals。在我们的使用中,其实没法直接做到这样的效果。
但是仿造
Babel的做法,我们可以整理一下自己的思路:
- 通过正则把插值和实际字符串拆开
- 通过
eval
或者new Function()
实现插值的计算 - 通过 concat 拼接,也可以使用 String.raw
代码实现如下:
var str = "string text ${1 + 2} string text ${2 + 3} test"; function template(str) { var pattern = /\$\{.*?\}/g; var patternCapture = /\$\{(.*?)\}/g; // 将非插值字符串分割出来 var strArr = str.split(pattern); // 将插值字符串分割出来 var rawArr = str .match(patternCapture) .map(item => item.replace(patternCapture, "$1")); // eval转换 var valueArr = rawArr.map(r => eval(r)); // 使用reduce和concat拼接, return strArr.reduce( (acc, curr, index) => acc.concat(curr, valueArr[index] || ""), "" ); // 或者使用String.raw // return String.raw({ raw: strArr }, ...valueArr); } console.log(template(str));
new Function
上面使用
eval对插值进行了求值,实际上在平时使用中,
eval是不推荐的。而且用
eval去解析一些循环判断和条件判断也不是很方便。
所以接下来使用
new Function()去构建一个模板函数。在这之前,需要说明一下
new Function的用法。
new Function ([arg1[, arg2[, ...argN]],] functionBody)
前面传入的是函数所需要的参数,最后是函数体,函数体是一个包括函数定义的 JavaScript 语句字符串。
其次,根据上面的插值实现,我们可以使用字符串拼接把插值计算之后和正常的字符串拼接起来。
对于简单插值,使用
{{}}包裹,而语句使用
{{~}}区别。下面是一个简单实现
function render(tem, data) { let template = tem; template = template .replace(/[\r\n\t]/g, "") .replace(/\{\{~(.+?)\}\}/g, (_, p1) => { return '";' + p1 + ' out+="'; }) .replace(/\{\{(.+?)\}\}/g, (_, p1) => { return '"; out+=""+' + p1 + '+""; out+="'; }); template = 'var out=""; out += "' + template + '";return out;'; var _render = new Function(...Object.keys(data), template); return _render(...Object.keys(data).map(k => data[k])); } var template = "test array{{~for (var i in group.jobs) {}}{{group.jobs[i]}} {{~}}} test obj {{group.jobs[1]}} {{group.name}} leader是{{leader}}"; var data = { group: { name: "group1", jobs: ["job1", "job2"] }, leader: "张三" }; console.log(render(template, data));
在给模板注入数据时,可以使用
with(data){}的方式,我不喜欢使用
with,所以把参数分解后传入了。
(完)。
相关文章推荐
- x-template:一个简单高效的字符串模板引擎
- Epii.js 一个极其简单的Js模板引擎
- 默默简单的写了一个模板引擎
- 200行python代码实现一个类似django的简单模板引擎
- 写了一个最简单的 js 模板引擎,直接贴代码
- 【python】简单实现一个模板引擎
- Epii.js 一个极其简单的Js模板引擎
- .net c# 一个简单但是功能强大动态模板引擎
- 教你使用javascript简单写一个页面模板引擎
- 一个简单的模板引擎
- 分享一个简单的python模板引擎
- php 编写一个简单的模板引擎
- 新手开发asp.net模板引擎(1): 一个简单的模板
- x-template:一个简单高效的字符串模板引擎
- sdcms的模板解析引擎,一个非常简单和实用的CMS
- 一个前端攻城狮的全栈之路第四弹:jade模板引擎的简单介绍和使用
- 新手开发asp.net模板引擎(1): 一个简单的模板
- 分享一个简单的python模板引擎
- 教你使用javascript简单写一个页面模板引擎
- 默默简单的写了一个模板引擎