Handlebars学习之——块表达式

**Block helper可以让你自定义迭代器和其他可以传入新的上下文的功能** # 基本块 Block helper的定义方法是:在一个mustache中,以`#`开头,后面跟着helper的名称,然后对应的在一个mustache中以`/`开头,加上相同的名称作为这个块的结尾。 形如:
1
2
3
{{#hello}}
{{item}}
{{/hello}}
在helper中,function接收一个hash参数options,而options有个fn方法,该方法可接收一个context参数来改变block中的上下文,返回一个类似于编译后的Handlebars模板,明确地说,就是一个字符串。
1
2
3
Handlebars.registerHelper('hello', function(options){
return options.fn(this);
});
在上面的代码中,我们给options.fn传入了一个新的上下文,这个新的context是this,就是代表当前的上下文,因此,如果当前的上下文是:
1
2
3
4
5
{
title: 'This is the title.',
body: 'body',
item: 'item'
}
那么block中的item标识符最终返回字符串`'item'` 注:以这种方式定义的helper,在模板中,可以使用path,如上面的`{{item}}`可以写成`{{./item}}` # with helper(内置) with helper会把传入的context直接调用,实现如下
1
2
3
Handlebars.registerHelper('with', function(context, options) {
return options.fn(context);
});
当处理json的时候用with比较方便
1
2
3
4
5
6
7
<div class="entry">
<h1>{{title}}</h1>
{{#with story}}
<div class="intro">{{{intro}}}</div>
<div class="body">{{{body}}}</div>
{{/with}}
</div>
context:
1
2
3
4
5
6
7
{
title: "First Post",
story: {
intro: "Before the jump",
body: "After the jump"
}
}
# 简单迭代器 先来看一下内置的each helper是怎么实现的
1
2
3
4
5
6
7
8
<div class="comments">
{{#each comments}}
<div class="comment">
<h2>{{subject}}</h2>
{{{body}}}
</div>
{{/each}}
</div>
helper:
1
2
3
4
5
6
7
8
9
Handlebars.registerHelper('each', function(context, options) {
var ret = "";

for(var i=0, j=context.length; i<j; i++) {
ret = ret + options.fn(context[i]);
}

return ret;
});
其实就是在helper中遍历了一次context。明白了这一点,我们就可以对其进行改造,实现自定义的迭代器了。如:
1
2
3
{{#list nav}}
<a href="{{url}}">{{title}}</a>
{{/list}}
context:
1
2
3
4
5
6
{
nav: [
{ url: "http://www.yehudakatz.com", title: "Katz Got Your Tongue" },
{ url: "http://www.sproutcore.com/block", title: "SproutCore Blog" },
]
}
helper:
1
2
3
4
5
6
7
8
9
Handlebars.registerHelper('list', function(context, options) {
var ret = "<ul>";

for(var i=0, j=context.length; i<j; i++) {
ret = ret + "<li>" + options.fn(context[i]) + "</li>";
}

return ret + "</ul>";
});
# 条件表达式 Handlebars中内置的if只能判断true/false,具体实现如下:
1
2
3
4
5
{{#if isActive}}
<img src="star.gif" alt="Active">
{{else}}
<img src="cry.gif" alt="Inactive">
{{/if}}
helper:
1
2
3
4
5
6
7
Handlebars.registerHelper('if', function(conditional, options) {
if(conditional) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
其中,`options.inverse`用来处理block中的else语句,对此,我们也可以实现自定义的条件helper来增强条件语句的功能
1
2
3
4
5
6
7
Handlebars.registerHelper('equal' function(param1, param2, options) {
if(param1 == param2) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
1
2
3
4
5
{{#equal 'hello' 'world'}}
<p>==</p>
{{else}}
<p>!=</p>
{{/equal}}
以上示例展示了判断两个变量相等或不等时执行的操作。 此外,Handlebars支持链式的条件语句,如
1
2
3
4
5
{{#if isActive}}
<img src="star.gif" alt="Active">
{{else if isInactive}}
<img src="cry.gif" alt="Inactive">
{{/if}}
# hash参数 hash arguments在之前的文章有提到过,就是将一些键值对序列作为helper回调函数最后一个参数的值,通过`options.hash`来访问。
1
2
3
{{#list nav id="nav-bar" class="top"}}
<a href="{{url}}">{{title}}</a>
{{/list}}
1
2
3
4
5
6
7
8
9
Handlebars.registerHelper('list' function(context, options) {
var attrs = Em.keys(options.hash).map(function(key) {
return key + '="' + options.hash[key] + '"';
}).join(" ");

return "<ul " + attrs + ">" + context.map(function(item) {
return "<li>" + options.fn(item) + "</li>";
}).join("\n") + "</ul>";
});
# 块参数 Handlebars 3.0的新特性。
1
2
3
{{#each users as |user userId|}}
Id: {{userId}} Name: {{user.name}}
{{/each}}
这边`user`会取当前context的值,而`userId`会取当前遍历context的索引值。 有点类似于JavaScript里的Array.map # raw helper 之前也提到过,用来转义的
1
2
3
{{{{raw-helper}}}}
{{bar}}
{{{{/raw-helper}}}}
helper:
1
2
3
Handlebars.registerHelper('raw-helper', function(options) {
return options.fn();
});
输出:
1
{{bar}}
# 参考 * [Handlebars.js: Minimal Templating on Steroids][]