精巧快速的前端模板引擎doT

  在没有接触模板引擎之前,我们接受后台传来的json数据后需要将其拼接成字符串,然后将其插入到DOM中去,如果有一些复杂的业务逻辑,拼接代码会变得更加的繁琐,而且后期维护起来也十分的不方便。后来在项目中接触到一款十分强大的模板引擎,就是我们的doT,被它强大的功能深深的吸引住了。尤其在1.0.0版本后还新增了局部模板的功能,可扩展性非常的强大。刚开始看官方的文档时对局部模板这个功能还不是很懂,后来在网上搜寻了各种资料,才豁然开朗,分享一下自己的心得体会。

介绍

  doT模板引擎是一个最快速最简洁的JavaScript模板引擎,在浏览器端和Nodejs端都适用。它小巧快速并且没有任何依赖,所有代码才一百多行,压缩后才4k,非常的轻量。

stage

配置

  在doT文件中有一个templateSettings属性用来配置doT的定界符(官方文档这么称呼,我们可以理解为模板的语法),我们也可以手动修改使用自己的定界符,但是建议使用默认的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
templateSettings: {
evaluate: /\{\{([\s\S]+?(\}?)+)\}\}/g,
interpolate: /\{\{=([\s\S]+?)\}\}/g,
encode: /\{\{!([\s\S]+?)\}\}/g,
use: /\{\{#([\s\S]+?)\}\}/g,
useParams: /(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,
define: /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
defineParams:/^\s*([\w$]+):([\s\S]+)/,
conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,
iterate: /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
varname: "it",
// 控制空白字符,true - 全部去掉,false - 保留
strip: true,
// 性能优化设置,通过它调整性能,append 设置成 false,可能会产生更好的效果
append: true,
// 如果 'selfcontained' 为 true,doT 将毫无依赖的产生函数
selfcontained: false,
doNotSkipEncoded: false
},

  在配置中有一个属性是varname,它的值是it,代表了在模板中传入对象所使用的变量名。

用法

  首先介绍一下doT模板中常用的定界符代表的使用和含义:

1
2
3
4
5
6
7
{{= }}    用于插值(interpolation)
{{ }} 用于求值(evaluation)
{{? }} 条件语句
{{~ }} 数组迭代
{{! }} 用于编码求值
{{# }} 用于编译时求值/引入和局部模板
{{## #}} 用于编译时定义

赋值定界符

  首先定义要赋值的模板,注意模板的type要写成text/x-dot-template。

1
2
3
4
<script id="templ1" type="text/x-dot-template">
<div>Hi {{=it.name}}!</div>
<div>Your age is {{=it.age || ''}}</div>
</script>

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里

  在这里我们使用了的赋值定界符,用于在模板中进行赋值操作。这里使用的it就是我们在上面配置中定义好的varname变量。然后在JS中调用模板渲染到页面上去:

1
2
3
4
var person = {'name':'ace','age':20},
person1 = {'name':'john','age':21};
var doTemplate = doT.template($('#templ1').html());
$('body').html(doTemplate(person)+doTemplate(person1));

  在这里我们获取到了模板函数doTemplate,然后将定义好的对象传入函数中,最后返回我们所需要的字符串插入到DOM中。这里我们对doTemplate函数进行了一次复用,定义了两个属性相同字面量传入。

求值定界符

  如果传入到模板中的是一个对象,我们还可以通过求值定界符遍历输入对象中的属性:

1
2
3
4
5
<script id="templ2" type="text/x-dot-template">
{{ for(var prop in it) { }}
<div>key:{{= prop }} --- value:{{= it[prop] }}</div>
{{ } }}
</script>

  在求值定界符中,我们可以写类似于js的语法。

1
2
3
var dataEval = {"name":"ace","age":20,"interests":"basketball","email":"ace@ly.com","phone":"110"};
var evalText = doT.template($("#templ2").html());
$('body').html(evalText(dataEval));

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里

迭代定界符

  有时候我们需要遍历对象中的数组,通过迭代定界符来遍历。但是要在但是需要在后面加上:value:index表示数组中的每个元素和索引值。

1
2
3
4
5
<script id="templ3" type="text/x-dot-template">
{{~it.array:value:index}}
<div>index:{{= index+1 }}--value:{{= value }}!</div>
{{~}}
</script>

  在这里我们传入的是一个对象,所以需要用~it.array来遍历我们的数组。

1
2
3
var dataArr = {"array":["banana","apple","orange"]};
var arrText = doT.template($("#templ3").html());
$('body').html(arrText(dataArr));

  我们可以直接传入一个数组,遍历的时候就需要用~it直接来遍历数组值。

条件定界符

  在模板中有时候我们需要对数据进行判断,进行不同的展示,这时我们就需要用到条件定界符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script id="templ4" type="text/x-dot-template">
<div>姓名:{{=it.name}}</div>
<div>成绩:{{=it.score}}</div>
{{? it.score<60}}
<div>等级:不及格</div>
{{?? it.score<70}}
<div>等级:及格</div>
{{?? it.score<80}}
<div>等级:良好</div>
{{?? it.score<90}}
<div>等级:优秀</div>
{{?? it.score<100}}
<div>等级:棒极了</div>
{{??}}
<div>等级:数据有误</div>
{{?}}
</script>

  条件模板前后都用单问号包裹,中间的双问号表示else。

1
2
3
var student = {'name':'ace','score':82}
var conditionText = doT.template($('#templ4').html());
$('body').html(conditionText(student))

  对于条件判断,我们还可以使用求值定界符,对上面的进行如下改写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script id="templ4" type="text/x-dot-template">
<div>姓名:{{=it.name}}</div>
<div>成绩:{{=it.score}}</div>
{{ if(it.score<60) { }}
<div>等级:不及格</div>
{{ } else if(it.score<70) { }}
<div>等级:及格</div>
{{ } else if(it.score<80) { }}
<div>等级:良好</div>
{{ } else if(it.score<90) { }}
<div>等级:优秀</div>
{{ } else if(it.score<100) { }}
<div>等级:棒极了</div>
{{ } else { }}
<div>等级:数据有误</div>
{{ } }}
</script>

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里

模板定界符(doT新增功能)

  在1.0.0之后的版本,doT加入的局部模板的功能,我们在模板中还可以定义一个局部模板。在主模板和子模板中我们都可以通过it变量引用到传入的对象。

1
2
3
4
5
6
7
8
9
10
11
<script id="templ6" type="text/x-dot-template">
// 定义主模板
{{##def.father:
<div>主模板:{{=it.name}}</div>
子模板1:{{#def.child1}}
子模板2:{{#def.child2}}
#}}
// 编译时输入主模板
{{#def.father}}
{{=it.html}}
</script>

  首先通过两个#定义一个编译的需要引入局部模板的主模板def.father,在它里面定义了两个子模板def.child1和def.child2,然后通过一个#在编译时输入我们的主模板。如果没有这段输入代码,那么最后在编译时doT不会帮我们输出主模板的。

1
2
3
4
5
6
7
8
9
10
11
var dataPart = {
"name":"Corner",
"age":31,
"html":"<div style='background: #f00; height: 30px; line-height: 30px;'>html元素</div>"
};
var defPart = {
"child1":"<div>{{=it.name}} who?</div>",
"child2":"<div>{{=it.name}} how?</div>"
};
var partText = doT.template($("#templ6").html(), undefined, defPart);
$("body").html(partText(dataPart));

  在JS中我们首先定义需要传入的数据,然后定义一个子模板的对象。这个对象中包含了我们在模板中定义的两个子模板的名称和内容,在子模板内容中,我们还是通过it变量引用到传入的对象。然后在生成模板函数时我们将子模板的对象一起传给template。


本网所有内容文字和图片,版权均属谢小飞所有,任何媒体、网站或个人未经本网协议授权不得转载、链接、转贴或以其他方式复制发布/发表。如需转载请关注公众号【前端壹读】后回复【转载】。