对比了几个 Node.js 常用模板,什么 EJS 、Jade 等等,还是感觉 Handlebars 比较顺手,模板只做数据展示,前端逻辑的东西通过 helper 实现,HTML 中没有掺杂太多 JS 的东西,看起来整洁一些。
Express 中引入 Handlebars 模板的话,需要引入hbs 模块
handlebars 表达式
<h1>{{title}}</h1>
在上下文中找 title 属性,获取它的值
点分割表达式
<h1>{{article.title}}</h1>
当前上下文找 article 属性,再找它的 title 属性
标识符可以是除了以下字符以外的 unicode 字符 Whitespace ! “ # % & ‘ ( ) * + , . / ; < = > @ [ \ ] ^ ` { | } ~
不合法的标识符用 “[]” 包装
this
不转义
hash
Helpers
0 或多个参数,用空格分割,每个参数是个 handlebars 表达式
key
link 是 helper 名字,story 是 helper 参数。
注册 helper
value
helper 返回 HTML ,不想被转义,用 Handlebars.SafeString()
。
helper 把接收的上下文作为 this
上下文
value
上下文和 helper:
this
@first
输出结果:
@last
也可以直接传字符串参数
@first
等价于
false
undefined
helper 最后一个参数也可以接收可选的键值对序列(文档提到的 hash
参数)
null
hash 参数的 key
必须是简单的标识符,value
是 Handlebars 表达式,value
可以是简单的标识符,路径,或者字符串。
""
基础 Blocks
[]
if
noop helper 实际跟没有 helper 类似,只是传递上下文,返回字符串。Handlebars 把当前的上下文作为 this
。
内建 helper
with helper
根据模板传递的上下文解析模板
unless
当 JSON 对象包含嵌套属性时,不必再三重复父属性的名字。比如以下数据:
unless
helper 接收参数,参数为 JSON 属性的 上下文。
if
简单迭代器 each helper
Handlebars 内建了 each 迭代器
false
实现原理如下: 把 comments 数组的每一个元素作为上下文解析模板
<script>
可以用 this 引用迭代元素
Handlebars.compile
上下文:
Handlebars.SafeString
结果:
new Handlebars.SafeString(result)
当某一项为空时,可以用
Handlebars.registerHelper('link', function(text, url) {
text = Handlebars.Utils.escapeExpression(text);
url = Handlebars.Utils.escapeExpression(url);
var result = '<a href="' + url + '">' + text + '</a>';
return new Handlebars.SafeString(result);
});
表达式
{{! }}
通过
{{!-- --}}
可以引用当前的循环索引
<div class="entry">
{{! only output this author names if an author exists }}
{{#if author}}
<h1>{{firstName}} {{lastName}}</h1>
{{/if}}
</div>
用
<div class="entry">
{{! This comment will not be in the output }}
<!-- This comment will be in the output -->
</div>
引用当前的键名:
{{> partialName}}
数组迭代的第一步和最后一步用 @first
和 @last
变量表示, 对象迭代时仅 @first
可用。
条件语句 if helper
如果条件参数返回 false
, undefined
, null
, ""
或 []
(非真的值)时,Handlebars 将不渲染该块
Handlebars 内建了 if
和 unless
语句
var source = "<ul>{{#people}}<li>{{> link}}</li>{{/people}}</ul>";
实现原理:根据传入的条件参数,判断是否解析模板
Handlebars.registerPartial('link', '<a href="/people/{{id}}">{{name}}</a>')
var template = Handlebars.compile(source);
Handlebars 还提供了 else 语句
var data = { "people": [
{ "name": "Alan", "id": 1 },
{ "name": "Yehuda", "id": 2 }
]};
template(data);
// Should render:
// <ul>
// <li><a href="/people/1">Alan</a></li>
// <li><a href="/people/2">Yehuda</a></li>
// </ul>
unless helper
unless
跟 if
正好相反,如果表达式返回 false ,模板将被渲染。
Handlebars.Utils.escapeExpression(string)
当 license 返回 false
,Handlebars 将渲染 warning 。
log helper
记录上下文状态
Handlebars.Utils.isEmpty(value)
JavaScript 编译模板
模板可以包含在特殊的<script>
里:
Handlebars.Utils.extend(foo, {bar: true})
然后用 Handlebars.compile
编译模板
Handlebars.Utils.toString(obj)
获取编译后的 HTML 模板,用 JSON 数据填充模板
Handlebars.Utils.isArray(obj)
最终结果:
Handlebars.Utils.isFunction(obj)
HTML 转义
不想转义用
undefined
模板:
undefined
上下文数据:
undefined
最终结果:
undefined
Handlebars.SafeString
方法不做转义,通常返回 new Handlebars.SafeString(result)
。此种情形,你可能想手动转义参数:
Handlebars.registerHelper('link', function(text, url) {
text = Handlebars.Utils.escapeExpression(text);
url = Handlebars.Utils.escapeExpression(url);
var result = '<a href="' + url + '">' + text + '</a>';
return new Handlebars.SafeString(result);
});
模板注释
{{! }}
或者
{{!-- --}}
<div class="entry">
{{! only output this author names if an author exists }}
{{#if author}}
<h1>{{firstName}} {{lastName}}</h1>
{{/if}}
</div>
模板注释不会输出,HTML 注释会输出
<div class="entry">
{{! This comment will not be in the output }}
<!-- This comment will be in the output -->
</div>
Partials 局部模板
用
{{> partialName}}
引入局部模板,局部模板可以使字符串,也可以是编译模板的函数。
var source = "<ul>{{#people}}<li>{{> link}}</li>{{/people}}</ul>";
Handlebars.registerPartial('link', '<a href="/people/{{id}}">{{name}}</a>')
var template = Handlebars.compile(source);
var data = { "people": [
{ "name": "Alan", "id": 1 },
{ "name": "Yehuda", "id": 2 }
]};
template(data);
// Should render:
// <ul>
// <li><a href="/people/1">Alan</a></li>
// <li><a href="/people/2">Yehuda</a></li>
// </ul>
内建工具
转义字符串
Handlebars.Utils.escapeExpression(string)
判断空值
Handlebars.Utils.isEmpty(value)
扩展对象
Handlebars.Utils.extend(foo, {bar: true})
转字符串
Handlebars.Utils.toString(obj)
判断数组
Handlebars.Utils.isArray(obj)
判断函数
Handlebars.Utils.isFunction(obj)