Handlebars库是另一个模板引擎。他继承自Mustache,所以大部分语法是兼容Mustance的。但Handlebars也新增了很多特性,比如superset。
在设计上,Handlebars不同于Jade,他不允许在模板里写很多JavaScript逻辑,这有助于保持模板的简洁和严格相关的数据表示。
Jade和Handlebars的另一个显著的不同是,Handlebars要求书写完整的HTML代码,正是由于这个原因,他可以不那么关心空格和缩进。
Handlebars的表达式是{{内容}}。 如:
<h1>{{title}}</h1> <p>{{body}}</p>对应的数据:
{ title: "Express.js Guide", body: "The Comprehensive Book on Express.js" }渲染后:
<h1>Express.js Guide</h1> <p>The Comprehensive Book on Express.js</p>在Handlebars中,each是一个内置的helpers,可以迭代对象和数组。当遍历的是对象时,在循环体中可以使用@key; 当遍历的是数组时,在循环体中可以使用@index。另外,this指向每一个循环项item。当item本身是一个对象时,this可以省略,只要写属性的名字就可以取到该属性的值。 如:
<div> {{#each languages}} <p>{{@index}}. {{this}}</p> {{/each}} </div>对应的数据:
{languages: ['php', node', 'ruby']}编译后输出的HTML代码如下:
<div> <p>0. php</p> <p>1. node</p> <p>2. ruby</p> </div>默认情况下,Handlebars会对变量的值进行转义。如果不想转义某个值,可以用三个大括号{{{和}}} 如:
{ arr: [ '<a>a</a>', '<i>italic</i>', '<strong>bold</strong>' ] }模板:
<ul> {{#each arr}} <li> <span>{{@index}}</span> <span>unescaped: {{{this}}} vs. </span> <span>escaped: {{this}}</span> </li> {{/each}} </ul>渲染后:
<ul> <li> <span>0</span> <span>unescaped: <a>a</a> vs. </span> <span>escaped: <a>a</a></span> </li> <li> <span>1</span> <span>unescaped: <i>italic</i> vs. </span> <span>escaped: <i>italic</i></span> </li> <li> <span>2</span> <span>unescaped: <strong>bold</strong> vs. </span> <span>escaped: <strong>bold</strong></span> </li> </ul>if是另一个内置的helper,用符号# 如:
{{#if user.admin}} <button class="launch">Launch Spacecraft</button> {{else}} <button class="login">Log in</button> {{/if}}数据:
{ user: { admin: true } }渲染后:
<button class="launch">Launch Spacecraft</button>这个内置的helper与if语句刚好相反。比如,前面的代码片段可以用unless语句重写。
{{#unless user.admin}} <button class="launch">Launch Spacecraft</button> {{else}} <button class="login">Log in</button> {{/unless}}渲染后:
<button class="login">Log in</button>当有很多个有内嵌属性的对象时,我们可以使用with传递上下文。比如,用下面的代码处理用户的联系方式和地址信息:
{{#with user}} <p>{{name}}</p> {{#with contact}} <span>weibo: @{{weibo}}</span> {{/with}} <span>Address: {{address.city}}, {{/with}} {{user.address.state}}</span>接着用下面的数据填充模板。注意属性的名字和Handlebars模板中唯一的user对象的名字是相同的:
{user{ contact: { email: 'lijian@weixin.com', weibo: '深情小建' }, address: { city: 'beijin', state: 'China' }, name: 'lijian' }}渲染后:
<p>lijian</p> <span>weibo: @深情小建</span> <span>Address: beijin, China </span>想要输出注释,可以使用常规的HTML注释<!---->. 若要在最终的输出中隐藏注释,那就使用{{!}},或者{{!----}} 如:
<!--content goes here--> <p>Node.js is a non-blocking I/O for scalable apps.</p> {{! @todo change this to a class}} {{!-- add the example on {{#if}} --}} <p> id="footer">Copyright 2015 lijian</p>输出:
<!-- content goes here --> <p>Node.js is a non-blocking I/O for scalable apps.</p> <p> id="footer">Copyright 2015 lijian</p>自定义的Handlebars helper和内置的helper块相似,也和Jade中的mixin相似。想要使用自定义helpers,就需要像创建JavaScript函数那样去创建他们,并且用Handlebars instance去注册。
下面的这个Handlebars模板使用了自定义的helper table,我们会在后面的JavaScript/Node.js代码中注册table:{{table nod}}
JavaScript/Node.js会告诉Handlebars的编译器,当遇到自定义的table函数时做什么 如:
Handlebars.registerHelper('table', function(data){ var str = '<table>'; for (var i=0; i<data.length; i++){ str += '<tr>'; for (var key in data[i]){ str += '<td>' + data[i][key] + '</td>'; }; str += '</tr>'; }; str += '</table>'; return new Handlebars.SafeString(str); });table的数据:
{ node:[ {name: 'express', url:'http://expressjs.com/'}, {name: 'hapi', url:'http://spumko.github.io/'}, {name: 'compound', url:'http://compoundjs.com/'}, {name: 'derby', url:'http://derbyjs.com/'} ] }生成的HTML输出:
<table> <tr> <td>express</td> <td>http://expressjs.com/</td> </tr> <tr> <td>hapi</td> <td>http://spumko.github.io/</td> </tr> <tr> <td>compound</td> <td>http://compoundjs.com/</td> </tr> <tr> <td>derby</td> <td>http://derbyjs.com/</td> </tr> </table>Handlebars中的Include是由表达式{{>partical_name}}解释的。包含的子模板和helper类似, 是用Handlebars.registerPartial(name, source)注册的,其中name是一个字符串,source是待包含的Handlebars子模板