# 块助手
块助手使得定义自定义迭代器和其他功能成为可能,这些功能可以使用新的上下文调用传递的块。
# 基本块
出于演示目的,我们定义一个块助手来调用该块,就好像不存在助手一样。
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,则助手应插入该 HTML 块。 Handlebars 通过为块助手提供通用 else
功能来解决这个问题。
Handlebars 为 else
片段提供块作为 options.inverse
。 你不需要检查 else 片段是否存在: Handlebars 会自动检测并注册 "noop" 功能。
Handlebars.registerHelper("if", function(conditional, options) {
if (conditional) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
Handlebars 通过将其附加为选项哈希的属性来为块助手提供额外的元数据。 继续阅读更多示例。
条件语句也可以通过在 else 小胡子中包含后续的辅助程序调用来链接。
没有必要在后续调用中使用相同的辅助程序,除非辅助程序可以像任何其他辅助程序一样在 else 部分中使用。 当辅助程序值不同时,结束胡须应与开始辅助程序名称匹配。
# 哈希参数
与常规助手一样,块助手可以接受可选的哈希作为其最终参数。 让我们重新审视 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
字段确定模板引用的块参数的数量,这是一个整数。 该值表示子模板可以引用的块参数的数量。 超出此计数的参数将永远不会被引用,并且如果需要,辅助程序可以安全地省略。 这是可选的,传递给模板的任何其他参数都将被默默忽略。
# 原始块
原始块可用于需要处理未处理的胡须块的模板。
将执行助手 raw 辅助程序而不解释内容。
Handlebars.registerHelper("raw-helper", function(options) {
return options.fn();
});
将渲染
{{bar}}