# 区块助手
区块助手使定义自定义迭代器和其他功能成为可能,这些功能可以调用传递的区块并使用新的上下文。
# 基本区块
为了演示目的,让我们定义一个区块助手,它像没有助手一样调用区块。
noop
助手(“无操作”的缩写)将接收一个选项哈希。此选项哈希包含一个函数(options.fn
),该函数的行为类似于普通的编译后的 Handlebars 模板。具体来说,该函数将接受一个上下文并返回一个字符串。
Handlebars.registerHelper("noop", function(options) {
return options.fn(this);
});
Handlebars 始终使用当前上下文作为 this
调用助手,因此您可以使用 this
调用区块以在当前上下文中评估区块。
以这种方式定义的任何助手都将优先于上下文中定义的字段。要访问被助手屏蔽的字段,可以使用路径引用。在上面的示例中,上下文对象上名为 noop
的字段将使用以下方式引用
# 基本区块变体
为了更好地说明语法,让我们定义另一个区块助手,它在包装的文本中添加一些标记。
粗体助手将添加标记以使它的文本变为粗体。与之前一样,该函数将接受上下文作为输入并返回一个字符串。
Handlebars.registerHelper("bold", function(options) {
return new Handlebars.SafeString('<div class="mybold">' + options.fn(this) + "</div>");
});
# with
助手
with
助手演示了如何将参数传递给助手。当助手使用参数调用时,它将使用模板传入的任何上下文调用。
如果您发现 JSON 对象的某个部分包含深度嵌套的属性,并且您希望避免重复父名称,那么您可能会发现这样的助手很有用。上面的模板可能与以下 JSON 结合使用
{
title: "First Post",
story: {
intro: "Before the jump",
body: "After the jump"
}
}
实现这样的助手非常类似于实现 noop
助手。助手可以接受参数,参数的评估方式与直接在 {{mustache}}
块中使用的表达式相同。
Handlebars.registerHelper("with", function(context, options) {
return options.fn(context);
});
参数按传递顺序传递给助手,然后是选项哈希。
# 简单迭代器
区块助手的常见用例是使用它们来定义自定义迭代器。实际上,所有 Handlebars 内置助手都定义为常规的 Handlebars 区块助手。让我们看看内置的 each
助手是如何工作的。
在这种情况下,我们希望为 comments 数组中的每个元素调用传递给 each
的区块一次。
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;
});
在这种情况下,我们迭代传递参数中的项目,使用每个项目调用区块一次。在迭代时,我们构建一个字符串结果,然后返回它。
此模式可用于实现更高级的迭代器。例如,让我们创建一个迭代器,它创建一个 <ul>
包装器,并将每个结果元素包装在 <li>
中。
您可以使用类似于以下内容作为上下文来评估此模板
{
nav: [
{ url: "http://www.yehudakatz.com", title: "Katz Got Your Tongue" },
{ url: "http://www.sproutcore.com/block", title: "SproutCore Blog" }
];
}
助手类似于原始的 each
助手。
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>";
});
使用 underscore.js 或 SproutCore 的运行时库之类的库可以使它更漂亮。例如,以下是使用 SproutCore 的运行时库时的样子
Handlebars.registerHelper("list", function(context, options) {
return (
"<ul>" +
context
.map(function(item) {
return "<li>" + options.fn(item) + "</li>";
})
.join("\n") +
"</ul>"
);
});
# 条件语句
区块助手的另一个常见用例是评估条件语句。与迭代器一样,Handlebars 的内置 if
和 unless
控制结构是作为常规的 Handlebars 助手实现的。
控制结构通常不会更改当前上下文,而是根据某个变量决定是否调用区块。
Handlebars.registerHelper("if", function(conditional, options) {
if (conditional) {
return options.fn(this);
}
});
在编写条件语句时,您通常希望使模板能够提供助手应插入的 HTML 块,如果条件语句评估为 false。Handlebars 通过为区块助手提供通用的 else
功能来解决此问题。
Handlebars 将 else
片段的区块提供为 options.inverse
。您不需要检查 else 片段是否存在:Handlebars 会自动检测它并注册一个“无操作”函数。
Handlebars.registerHelper("if", function(conditional, options) {
if (conditional) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
Handlebars 通过将它们附加为选项哈希的属性,为区块助手提供额外的元数据。继续阅读以获取更多示例。
条件语句也可以通过在 else mustache 中包含后续助手调用来链接。
在后续调用中使用相同的助手不是必需的,就像任何其他助手一样,可以在 else 部分使用 unless 助手。当助手值不同时,结束 mustache 应与开始助手名称匹配。
# 哈希参数
与常规助手一样,区块助手可以接受一个可选的哈希作为其最后一个参数。让我们重新审视 list
助手,并使我们能够向将要创建的 <ul>
元素添加任意数量的可选属性。
Handlebars 将最终哈希提供为 options.hash
。这使得接受可变数量的参数变得更容易,同时还接受可选的哈希。如果模板没有提供哈希参数,Handlebars 将自动传递一个空对象 ({}
),因此您不需要检查哈希参数是否存在。
Handlebars.registerHelper("list", function(context, options) {
var attrs = Object.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.registerHelper("list", function(context, options) {
var out = "<ul>",
data;
if (options.data) {
data = Handlebars.createFrame(options.data);
}
for (var i = 0; i < context.length; i++) {
if (data) {
data.index = i;
}
out += "<li>" + options.fn(context[i], { data: data }) + "</li>";
}
out += "</ul>";
return out;
});
通过 data
选项提供的私有变量在所有后代作用域中可用。
在父作用域中定义的私有变量可以通过路径查询访问。要访问父迭代器的 index
字段,可以使用 @../index
。
确保在每个助手中创建一个新的数据帧,并为其分配自己的数据。否则,下游助手可能会意外地修改上游变量。
还要确保在尝试与现有数据对象交互之前定义 data
字段。私有变量行为是条件编译的,某些模板可能不会创建此字段。
# 区块参数
Handlebars 3.0 中的新功能,可以从支持的助手接收命名参数。
在此特定示例中,user
将具有与当前上下文相同的值,而 userId
将具有迭代的索引值。
这允许嵌套助手避免使用私有变量可能发生的名称冲突。
许多 内置助手 支持区块参数,任何自定义助手都可以通过 blockParams
选项字段提供它们。
助手可以通过 options.fn.blockParams
字段确定模板引用的区块参数数量,该字段是一个整数计数。此值表示子模板可能引用的区块参数数量。超出此计数的参数永远不会被引用,如果需要,助手可以安全地省略它们。这是可选的,传递给模板的任何其他参数将被静默忽略。
# 原始区块
原始区块可用于需要处理未处理的 mustache 块的模板。
将执行助手 raw-helper 而不解释内容。
Handlebars.registerHelper("raw-helper", function(options) {
return options.fn();
});
将呈现
{{bar}}