渲染html到页面中,在koa中可以这么干:
- app.get('/',function*(){
 - this.body = "<p>'+title+'</p>";
 - })
 
但问题很大,模板混入到js逻辑了,非常不利于维护,基于 mvc 模式,我们需要将html模板抽离到 view 中方便维护,这时候我们就需要一款模板渲染引擎。
为什么选择xtemplate
适用于 koa 的模板引擎选择非常多,比如 jade、ejs、nunjucks、xtemplate 等。
为什么选择 xtemplate 呢?
上手难度
jade 无疑是最独特,上手难度最高,特别是将 html 转成 jade 风格的代码,需要一些成本和适应,特别是空格敏感,经常引起模块渲染报错:
- body
 - h1 Jade - node template engine
 - #container.col
 - if youAreUsingJade
 - p You are amazing
 - else
 - p Get on it!
 
但 jade 在 express 中拥有广泛的群众基础,所以从 express 转到 koa,jade 是个不错的选择,但我一直认为 jade 不是最佳的模板选择。
ejs、nunjucks、xtemplate 的上手难度差不多,但ejs的扩展写法有些诡异,特别是 filter 的写法:
- <p><%=: users | first | capitalize %></p>
 
xtemplate 相对于 nunjucks 的优势是,模板的逻辑写法体验更接近js(ejs的逻辑表达也很接近js),上手更为简单,来看下同样一个 if 判断的写法差异。
xtemplate:
- {{#if(variable===0)}}
 - It is true
 - {{/if}}
 
nunjucks:
- {% if variable == 0 %}
 - It is true
 - {% endif %}
 
所以上手难度:xtemplate < nunjucks < ejs < jade 。
功能的强大度
四款模板引擎必备几样功能都具备:变量、逻辑表达式、循环、layout、include、宏、扩展等。
nunjucks 无疑是功能最全面的模板引擎,xtemplate 拥有 nunjucks 大部分的特性,除了filter,但 xtemplate 拥有非常强悍的拓展性:
- xtpl.addCommand('money',function(scope, option){
 - var money = option.params[0];
 - if(typeof money !== 'number') return '';
 - //金额除以100(接口返回的金额都是以分为单位,转成元)
 - var s = Number(money)/100;
 - return s;
 - })
 
模板中使用:
- {{money(10000)}}
 
nunjucks 与 xtemplate 都拥有实用的宏定义功能:
- {{#macro("test","param", default=1)}}
 - param is {{param}} {{default}}
 - {{/macro}}
 
模板中使用:
- {{macro("test","2")}}
 
输出内容:
- param is 2 1
 
jade 中的 Mixins,ejs 中的 function 也可以实现类似的抽取公用html代码块的目的 。
如果真要分个高下:nunjucks > xtemplate > jade > ejs 。
是否支持前后端混用
jade 直接淘汰,相信在前端js领域一般不会选择 jade 来渲染。
nunjucks 也使用的比较少(ejs其实也少),更多人会选择使用 handlebars 。
xtemplate 目前在阿里的系统中前后端混用中已经得到论证,节约了模板前后端转换的时间。
事实上是否支持前后端混用不是决定性因素,特别是在 angularjs 盛行的年代。
性能考量
它们都很快,其实性能都不是问题,真要较真的话,xtemplate 会更优秀些,可以看 xtemplate benchmark。
个人觉得性能不是决定性因素。
基于上述几点考虑,推荐使用 xtemplate 。
		
 ArtTemplate_List 实例
		
		
 2016/08/02 16:56 | by 刘新修 ]
		ArtTemplate_List 实例1
- <!DOCTYPE HTML>
 - <html>
 - <head>
 - <meta charset="UTF-8">
 - <title>basic-demo</title>
 - <script src="../dist/template.js"></script>
 - </head>
 - <body>
 - <div id="content"></div>
 - <script id="test" type="text/html">
 - {{if isAdmin}}
 - <h1>{{title}}</h1>
 - <ul>
 - {{each list as value i}}
 - <li>索引 {{i + 1}} :{{value}}</li>
 - {{/each}}
 - </ul>
 - {{/if}}
 - </script>
 - <script>
 - var data = {
 - title: '基本例子',
 - isAdmin: true,
 - list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
 - };
 - var html = template('test', data);
 - document.getElementById('content').innerHTML = html;
 - </script>
 - </body>
 - </html
 
ArtTemplate_List 实例2
- <!DOCTYPE HTML>
 - <html>
 - <head>
 - <meta charset="UTF-8">
 - <title>compile-demo</title>
 - <script src="../dist/template.js"></script>
 - </head>
 - <body>
 - <h1>在javascript中存放模板</h1>
 - <div id="content"></div>
 - <script>
 - var source = '<ul>'
 - + '{{each list as value i}}'
 - + '<li>索引 {{i + 1}} :{{value}}</li>'
 - + '{{/each}}'
 - + '</ul>';
 - var render = template.compile(source);
 - var html = render({
 - list: ['摄影', '电影', '民谣', '旅行', '吉他']
 - });
 - document.getElementById('content').innerHTML = html;
 - </script>
 - </body>
 - </html>
 
- <!DOCTYPE HTML>
 - <html>
 - <head>
 - <meta charset="UTF-8">
 - <title>basic-demo</title>
 - <script src="../dist/template.js"></script>
 - </head>
 - <body>
 - <h1>在javascript中存放模板</h1>
 - <div id="content"></div>
 - <script>
 - /***** 小模版 *****/
 - var source=''
 - +'<ul>'
 - + '{{each list as value i}}'
 - + '<li>索引 {{i+1}} :{{value}}</li>'
 - + '{{/each}}'
 - +'</ul>';
 - /***** 定义变关联逻辑代码片段(小模版) *****/
 - var connectJs=template.compile(source);
 - /***** 最终的数据源等于==逻辑代码关联数据 *****/
 - var htmlData=connectJs({
 - list: ['摄影', '电影', '民谣', '旅行', '吉他']
 - });
 - /***** 把最终处理后的数据源插入到页面 *****/
 - document.getElementById('content').innerHTML=htmlData;
 - </script>
 - </body>
 - </html>
 
实例访问地址:http://code.liuxinxiu.com/jstpl/artTemplate/demo/best.html
include嵌入子模板:
- <!DOCTYPE HTML>
 - <html>
 - <head>
 - <meta charset="UTF-8">
 - <title>include-demo</title>
 - <script src="../dist/template.js"></script>
 - </head>
 - <body>
 - <div id="content"></div>
 - <script id="test" type="text/html">
 - <h1>{{title}}</h1>
 - {{include 'list'}}
 - </script>
 - <script id="list" type="text/html">
 - <ul>
 - {{each list as value i}}
 - <li>索引 {{i + 1}} :{{value}}</li>
 - {{/each}}
 - </ul>
 - </script>
 - <script>
 - var data = {
 - title: '嵌入子模板',
 - list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
 - };
 - var html = template('test', data);
 - document.getElementById('content').innerHTML = html;
 - </script>
 - </body>
 - </html>
 
理解部分(使用普通for循环加声明语法,进行数组遍历)1:
- <!DOCTYPE html>
 - <html lang="en">
 - <head>
 - <meta charset="UTF-8">
 - <title>AtrTemplate</title>
 - </head>
 - <body>
 - <div id="content"></div>
 - <script src="js/template-native.js"></script>
 - <script id="test" type="text/html">
 - <%for( i = 0; i < content.length; i++) {%>
 - <h1><%=content[i].title%></h1>
 - <p>条目内容 : <%=content[i].list%></p>
 - <%}%>
 - // 等同于普通的for循环,在普通的for循环上给每一行语法声明加上<% xx %>
 - // 等同于普通的for循环,在普通的for循环上取值部分加上类似jsp的变量声明 <%= xx %>
 - //for(i=0;i<content.length;i++){
 - // <h1><%=content[i].title%></h1>
 - // <p>条目内容 : <%=content[i].list%></p>
 - //}
 - </script>
 - <script>
 - /***** 自造数据,content为数组List便于测试循环 *****/
 - var data={
 - content:[
 - {
 - title: "artTemplate",
 - list: "新一代 javascript 模板引擎",
 - },
 - {
 - title: "特性",
 - list: "性能卓越,执行速度快"
 - }
 - ]
 - };
 - /***** 用template映射数据到逻辑代码区域|也可以理解称给逻辑代码片段绑定数据源 *****/
 - var html=template('test',data);
 - /***** 选择页面Dom元素,插入处理后的数据 *****/
 - document.getElementById("content").innerHTML=html;
 - </script>
 - </body>
 - </html>
 
理解部分(使用普通for循环加声明语法,进行双层嵌套数组遍历)2:
- <!DOCTYPE html>
 - <html lang="en">
 - <head>
 - <meta charset="UTF-8">
 - <title>AtrTemplate -- 简介</title>
 - </head>
 - <body>
 - <div id="content"></div>
 - <script src="js/template-native.js"></script>
 - <script id="listtemp">
 - </script>
 - <script id="test" type="text/html">
 - //循环嵌套,循环数组里的数组
 - <%for(i=0;i<content.length;i++){%>
 - <h1><%=content[i].title%></h1>
 - <ul>
 - <%for(j=0;j<content[i].list.length;j++){%>
 - <li><%=content[i].list[j]%></li>
 - <%}%>
 - </ul>
 - <%}%>
 - </script>
 - <script>
 - var data={
 - content:[
 - {
 - title: "artTemplate",
 - list:["新一代 javascript 模板引擎"]
 - },
 - {
 - title: "特性",
 - list: [
 - "性能卓越,执行速度通常是 Mustache 与 tmpl 的 20 多倍",
 - "支持运行时调试,可精确定位异常模板所在语句",
 - " 对 NodeJS Express 友好支持",
 - "安全,默认对输出进行转义、在沙箱中运行编译后的代码(Node版本可以安全执行用户上传的模板)",
 - " 支持include语句",
 - "可在浏览器端实现按路径加载模板",
 - "支持预编译,可将模板转换成为非常精简的 js 文件",
 - "模板语句简洁,无需前缀引用数据,有简洁版本与原生语法版本可选",
 - "支持所有流行的浏览器"
 - ]
 - }
 - ]
 - };
 - /***** 用template映射数据到逻辑代码区域|也可以理解称给逻辑代码片段绑定数据源 *****/
 - var html=template('test',data);
 - /***** 选择页面Dom元素,插入处理后的数据 *****/
 - document.getElementById("content").innerHTML=html;
 - </script>
 - </body>
 - </html>
 


  
 
 
 
 
 


