Handlebars 是一种简单的 模板语言。
它使用模板和输入对象来生成 HTML 或其他文本格式。Handlebars 模板看起来像常规的文本,但是它带有嵌入式的 Handlebars 表达式 。
<p>{{firstname}} {{lastname}}</p>
使用 npm 或 yarn
npm install handlebars # 或者 yarn add handlebars
通过 require
来使用 Handlebars
const Handlebars = require("handlebars"); const template = Handlebars.compile("Name: {{name}}"); console.log(template({ name: "张三" }));
Handlebars 表达式是一些以双花括号 {{}}
括起来的内容。
<p>{{firstname}} {{lastname}}</p>
Handlebars 表达式亦可为以句点分隔的路径。
{{person.firstname}} {{person.lastname}}
这个表达式将会在输入对象中查找 person
属性,然后查找 person
对象中的 firstname
和lastname
属性。 person 对象内的 属性。
一些诸如 #with
and #each
的助手代码使你能够操作嵌套的对象。当你在路径中包含 ../
时,Handlebars 将转回父级上下文。
{{#each people}} {{../prefix}} {{firstname}} {{/each}}
../
解析的确切值根据调用该代码块的助手代码不同而有所不同。仅在上下文更改必要时使用 ../
。诸如 {{#each}}
之类的子助 手代码将需要使用 ../
,而诸如 {{#if}}
之类的助手代码则不需要。
除了以下字符,标识符可以是任何 Unicode 文本:
Whitespace Whitespace、 ! 、"
、#
、 %
、&
、 '
、(
、)
、 *
、+
、 ,
、.
、/
、;
、<
、 =
、> 、@、[、`、 ]、^、{、|、 }、
除此之外,true
, false
, null
和 undefined
只允许在路径表达式的开头出现。
若想引用一个并非合法的标识符,你可以使用 [
。在路径表达式中你不必使用 ]
来关闭它,但其他表达式中是需要的。
在 Handlebars 中,由 {{expression}}
返回的值是 HTML 转义的。也就是说,如果一个表达式包含 &
,那么返回的 HTML 转义的内 容将会包含 &
。如果你不希望 Handlebars 转义字符的话,请使用 {{{
。
//传入以下模板 { specialChars: "& < > \" ' ` =" }
//raw: {{{specialChars}}} 未转义 raw: & < > " ' ` = //html-e 未转义scaped: {{specialChars}} 转义后 html-escaped: & < > " ' ` =
避免助手代码的返回值被HTML转义
即使当使用 {{
而非 {{{
来调用助手代码时,当你的助手代码返回一个 Handlebars.Safestring
的实例,返回值也并不会被转义 。你需要留心将所有参数正确地使用 Handlebars.escapeExpression
来转义。
Handlebars.registerHelper("bold", function(text) { var result = "<b>" + Handlebars.escapeExpression(text) + "</b>"; return new Handlebars.SafeString(result); });
助手代码可以实现一些并非 Handlesbars 语言本身的功能。
在运行时可以用 HandleBars.registerHelper
可以注册助手代码。例如为了将字符串中的所有字符转换为大写。
Handlebars.registerHelper('loud', function (aString) { return aString.toUpperCase() })
Handlebars 助手代码的调用需要一个简单标识符,且可紧接一个或多个参数(以空格分割)。每一参数为一个 Handlebars 表达式,且 将会用于上方“基本用法”中相同的方法来计算。
{{firstname}} {{loud lastname}}
此例子中,loud
是助手代码的名称,而 lastname
为传递给助手代码的参数。此模板,将会将输入的 uppercase
属性正确地转换 为大写
字面量参数:帮助代码调用亦可含字面量,作为参数抑或是 Hash 参数。支持的字面量有数字、字符串、true
, false
, null
及 undefined
含有Hash参数的助手代码
Handlebars 提供了额外的元数据,例如Hash参数来作为助手代码的最后一个参数
{{link "See Website" href=person.url class="person"}}
Hash 参数中的键必须为简单标识符,且值为 Handlebars 表达式。这意味着值可以为简单标识符,路径或字符串。
助手代码和属性查找时的消歧义
如果助手代码注册时的名称和一个输入的属性名重复,则助手代码的优先级更高。如果你想使用输入的属性,请在其名称前加 ./
或 this.
helper: {{name}} data: {{./name}} or {{this/name}} or {{this.name}}
options参数
除了在助手代码调用中运行的参数,options
也被作为一个额外的参数传递给助手代码。
对所有传递给助手代码的选项进行解释。
Handlebars 对子级表达式提供了支持,这使你可以在单个 Mustache 模板中调用多个助手代码,并且将内部助手代码调用的返回值作为 外部助手代码的参数传递。子级表达式使用括号定界。
{{outer-helper (inner-helper 'abc') 'def'}} //inner-helper 会被调用并带有字符串参数 'abc',同时不论 inner-helper 返回了什么, //返回值都将被作为第一个参数 传递给 outer-helper(同时 'def' 会作为第二个参数传递)。
通过在括号中添加一个 ~
字符,你可以从任何 Mustache 模板代码块的任何一侧省略模板中的空格。应用之后,该侧的所有空格将被 删除,直到第一个位于同一侧的 Handlebars 表达式或非空格字符出现。
{{#each nav ~}} <a href="{{url}}"> {{~#if test}} {{~title}} {{~^~}} Empty {{~/if~}} </a> {{~/each}}
{ nav: [{ url: "foo", test: true, title: "bar" }, { url: "bar" }]; } //输出 <a href="foo">bar</a><a href="bar">Empty</a>
Handlebars 可以从这两种方式中的任何一种转义:「内联转义」或「RAW 块助手代码」。内联转义通过 Mustache 代码块前置 \
实现 ,而 RAW 代码块通过使用 {{{{
实现。
\{{escaped}} {{{{raw}}}} {{escaped}} {{{{/raw}}}}
任何包含 }}
或其他 Handlebars 标记的注释都应该使用 {{!--}}
语法。
{{! This comment will not show up in the output}} <!-- This comment will show up as HTML-comment --> {{!-- This comment may contain mustaches like }} --}}
//输出 <!-- This comment will show up as HTML-comment -->
编译一个模板以立即运行:Handlebars.compile(template,options)
预编译:Handlebars.precompile(template,options)
设置已经被预编译的模板:Handlebars.template(templateSpec)
Handlebars.compile
与 Handlebars.precompile
函数构造了另一个函数。构造的函数可以用 template(context, options)
调用 。context
是输入的对象。
从 4.6.0 版本开始,由于各种安全原因, Handlebars 默认禁止访问原型的属性以及上下文对象的方法。以下选项可以用来控制原型的 可访问性。
Handlebars.registerPartial(name, partial)
:注册可以被当前环境内任意模版访问的代码片段;同时支持一次性注册多个代码片段;如果导入整个库,代码片段的值可能是按需编译的字符串。如果只是在运行时导入,代码片段必须为通过 Handlebars.template
预编 译过的模版。
//注册一个 Handlebars.registerPartial("foo", partial); //注册多个 Handlebars.registerPartial({ foo: partial, bar: partial });
Handlebars.unregisterPartial(name)
:注销之前注册过的代码片段。
Handlebars.unregisterPartial("foo");
Handlebars.registerHelper(name, helper)
:注册可以被当前环境中任意模版访问的助手代码;支持同时注册多个助手代码。
//注册一个 Handlebars.registerHelper("foo", function() {}); //注册多个 Handlebars.registerHelper({ foo: function() {}, bar: function() {} });
Handlebars.unregisterHelper(name)
:注销之前的注册的助手代码。
Handlebars.unregisterHelper("foo");
Handlebars.registerDecorator(name, helper)(已弃用)
:注册一个可以被环境内任意模版访问的装饰器;支持同时注册多个装饰器。
//注册一个 Handlebars.registerDecorator("foo", function() {}); //注册多个 Handlebars.registerDecorator({ foo: function() {}, bar: function() {} });
Handlebars.unregisterDecorator(name)
:注销一个之前注册的装饰器。
Handlebars.unregisterDecorator("foo");
Handlebars.create()
:创建一个独立的 Handlebars 环境。
var OtherHandlebars = Handlebars.create();
Handlebars.noConflict()
:从全局命名域中删除当前的 Handlebars 实例,重置全局 Handlebars
变量。
var myHandlebars = Handlebars.noConflict();
允许在无视版本冲突的情况下同时应用独立版本的库。
Handlebars.SafeString(string)
防止 string
在模版渲染时转义。
new Handlebars.SafeString("<div>HTML Content!</div>");
当构建将会被标记为安全的字符串时,为安全起见,任何外部内容都应该使用 Handlebars.escapeExpression
方法转义。
Handlebars.escapeExpression(string)
HTML 转义输入的字符串,使得字符串可以安全地在 HTML 内容中渲染为文字。
Handlebars.Utils.escapeExpression(string);
将字符串值里的&
, <
, >
, "
, '
, ``,
=用 HTML 实体的等效值替换。
SafeString
的值保持不变。
除了 {{{
表达式之外的表达式都将被本方法处理。为了防止可能的代码注入,帮助函数也应该在返回 HTML 内容时通过一个 SafeString
的实例来使用本函数。
本函数是 Handlebars.Utils.escapeExpression
的别名。
Handlebars.createFrame(data)
由块助手代码使用以创建子数据对象。
if (options.data) { var data = Handlebars.createFrame(options.data); data.foo = "bar"; options.data = data; }
Handlebars 提供了一大批由 Handlebars.Utils
对象暴露的应用函数。
Handlebars.Utils.isEmpty(value)
判断给定的值是否为空。
以上函数被内建的 if
与 with
助手代码应用以控制执行流。Handlebars 对于「空」的定义如下:
长度为 0 的数组
除了 0 以外的虚值
Handlebars.Utils.extend(obj, value)
简单的应用函数,用于使用 value
里定义的所有键来增强 obj
。
Handlebars.Utils.extend(foo, {bar: true})
将会将 foo
对象内的键 bar
对应的值设定为 true
。
Handlebars.Utils.toString(obj)
通用的 toString
方法。
Handlebars.Utils.isArray(obj)
判断对象是否为数组。
Handlebars.Utils.isFunction(obj)
判断对象是否为函数。
Handlebars.log(level, message)
被 log
助手代码使用的输出程序。
可能会在需要时被重载。
@data
变量是由 Handlebars 及其内建助手代码实现的。
初始化模版被执行时的上下文。
{{#each array}} {{@root.foo}} {{/each}}
除非特意改变,对于页面渲染时的每一部分,本项的值恒定。因此,当深度参数不能够引用它们的父模版时,本项可以在代码片段内使用 。
本项会被 each
助手代码在迭代的第一步被设置为 true。
{{#each array}} {{#if @first}} First! {{/if}} {{/each}}
从零开始的编号,表示当前的迭代次数。由 each
助手代码设置。
{{#each array}} {{@index}} {{/each}}
当前迭代次数的键。在遍历对象时被 each
助手代码设置。
{{#each array}} {{@key}} {{/each}}
在迭代的最后一步被 each
助手代码设置为 true。
{{#each array}} {{#if @last}} Last :( {{/if}} {{/each}}
设定 log 的输出级别。
template({}, { data: { level: Handlebars.logger.WARN } });
可以为以下值:Handlebars.logger.DEBUG
,Handlebars.logger.INFO
,Handlebars.logger.WARN
或者 Handlebars.logger.ERROR
默认值为 Handlebars.logger.ERROR
。
通过调用 Handlebars.registerHelper 方法,你可以从模板中的任何上下文中访问 Handlebars 助手代码。
Handlebars 允许代码片段的复用。代码片段是一段普通的 Handlebars 模板,但它们可以直接由其他模板调用。
通过 Handlebars.registerPartial
注册
Handlebars.registerPartial('myPartial', '{{prefix}}');
这个方法将注册代码片段 myPartial
。可以对代码片段进行预编译,并将预编译的模板传到第二个参数。
调用代码片段是通过「代码片段调用语法」完成的:
{{> myPartial }}
使用子表达式语法可以动态选择要执行的部分。
{{> (whichPartial) }}
template: '{{> (whichPartial) }}' partials: dynamicPartial: Dynamo! preparationScript: > Handlebars.registerHelper('whichPartial', function(context, options) { return 'dynamicPartial' }); input: null
输出:Dynamo!
通过将上下文传递给代码片段
template: '{{> myPartial myOtherContext }}' partials: myPartial: '{{information}}' preparationScript: | // Handlebars.registerHelper('loud', function(string) { // return string.toUpperCase() // }); input: myOtherContext: information: Interesting!
输出:Interesting!
可以通过 Hash 参数将自定义数据传递到代码片段。
template: '{{> myPartial parameter=favoriteNumber }}' partials: myPartial: 'The result is {{parameter}}' preparationScript: | // Handlebars.registerHelper('loud', function(string) { // return string.toUpperCase() // }); input: favoriteNumber: 123
输出:The result is 123
一般来讲,尝试渲染一个未注册的代码片段会抛出错误。如果需要阻止错误抛出,可以在代码块中嵌套代码片段。
template: | {{#> myPartial }} Failover content {{/myPartial}} preparationScript: | // Handlebars.registerHelper('loud', function(string) { // return string.toUpperCase() // }); input: null
输出:Failover content
这种代码块的语法也可以用于将模板传递到代码片段中。有专门的代码片段执行此操作:@partial-block
。
template: |- {{#> layout }} My Content {{/layout}} partials: layout: 'Site Content {{> @partial-block }}' preparationScript: | // Handlebars.registerHelper('loud', function(string) { // return string.toUpperCase() // }); input: null
输出:Site Content My Content
模板可以通过 inline
修饰符定义代码块范围之内的代码片段。
template: |- {{#*inline "myPartial"}} My Content {{/inline}} {{#each people}} {{> myPartial}} {{/each}} preparationScript: | // Handlebars.registerHelper('loud', function(string) { // return string.toUpperCase() // }); input: people: - firstname: Nils - firstname: Yehuda
输出:My Content
代码块表达式使你可以自定义这样的助手代码:这个助手代码可以使用与当前上下文不同的上下文来调用模板。这些块助手代码在名称前 以 # 号标识,并且需要一个名称相同的结束模板 /
。
{{#noop}}{{body}}{{/noop}}
函数接收一个上下文参数,并返回一个函数值
Handlebars.registerHelper("noop", function(options) { //this指针作为上下文传递,可以使用 this 调用该代码块以在上下文内使用代码块。 return options.fn(this); });
通过这种方式定义的任何助手代码将优先于上下文中定义的字段。若要访问助手代码中的字段,可以使用路径引用。
with
助手代码演示了如何将参数传递给你的助手代码。当将参数传递给助手代码时,模板传入的任何上下文中都会接收该参数。
<div class="entry"> <h1>{{title}}</h1> {{#with story}} <div class="intro">{{{intro}}}</div> <div class="body">{{{body}}}</div> {{/with}} </div>
//with代码助手 Handlebars.registerHelper("with", function(context, options) { return options.fn(context); });
块助手代码的一个常见用法是使用它们来定义自定义迭代器。实际上,所有 Handlebars 内置助手代码都被定义为是常规的 Handlebars 帮助器。
//迭代的使用方法 <div class="comments"> {{#each comments}} <div class="comment"> <h2>{{subject}}</h2> {{{body}}} </div> {{/each}} </div>
//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; });
块助手代码的另一个常见用例是计算条件表达式。Handlebars 内置有 if
和 unless
块助手代码。
{{#if isActive}} <img src="star.gif" alt="Active"> {{else}} <img src="cry.gif" alt="Inactive"> {{/if}}
//if else 代码块 Handlebars.registerHelper("if", function(conditional, options) { if (conditional) { return options.fn(this); } else { return options.inverse(this); } });
与普通的助手代码一样,块助手代码可以接受可选的 Hash 作为其最终参数。
{{#list nav id="nav-bar" class="top"}} <a href="{{url}}">{{title}}</a> {{/list}}
Handlebars 在 options.hash
中提供最后一个 Hash。这样可以更轻松地接受可变数量的参数,同时也接受可选的 Hash。如果模板未 提供 Hash 参数,则 Handlebars 将自动传递空对象({}
),因此你无需检查 Hash 参数是否存在。
这是 Handlebars 3.0 中的新增功能,可以从支持的助手代码中接收命名参数。
{{#each users as |user userId|}} Id: {{userId}} Name: {{user.name}} {{/each}}
RAW 代码块可用于处理不经由 mustache 模板处理的代码块。
{{{{raw-loud}}}} {{bar}} {{{{/raw-loud}}}}
你可以使用 if
助手代码来根据条件渲染代码块。如果其参数返回 false
、undefined
、null
、""
、 0
或者 []
,Handlebars 将不会渲染该块。
template: |- <div class="entry"> {{#if author}} <h1>{{firstName}} {{lastName}}</h1> {{/if}} </div> preparationScript: | // Handlebars.registerHelper('loud', function(string) { // return string.toUpperCase() // }); input: author: true firstName: Yehuda lastName: Katz
//输出 <div class="entry"> <h1>Yehuda Katz</h1> </div>
如果输入是空的 JSONObject {}
,则if
条件失败,输出:
<div class="entry"></div>
子表达式
建议使用助手代码向模板添加逻辑。你可以编写助手代码并将其应用到子表达式中。
template: | {{#if (isdefined value1)}}true{{else}}false{{/if}} {{#if (isdefined value2)}}true{{else}}false{{/if}} preparationScript: | Handlebars.registerHelper('isdefined', function (value) { return value !== undefined; }); input: value1: {}
//输出 true false
你可以将 unless
助手代码看作与 if
助手代码相反。如果表达式返回 false 则将渲染代码块。
template: |- <div class="entry"> {{#unless license}} <h3 class="warning">WARNING: This entry does not have a license!</h3> {{/unless}} </div> preparationScript: | // Handlebars.registerHelper('loud', function(string) { // return string.toUpperCase() // });
//输出 <div class="entry"> <h3 class="warning">WARNING: This entry does not have a license!</h3> </div>
你可以使用内置的 each
助手代码遍历列表。在块内,你可以使用 this
来引用被迭代的元素。
template: |- <ul class="people_list"> {{#each people}} <li>{{this}}</li> {{/each}} </ul> preparationScript: | // Handlebars.registerHelper('loud', function(string) { // return string.toUpperCase() // }); input: people: - Yehuda Katz - Alan Johnson - Charles Jolley
//输出 <ul class="people_list"> <li>Yehuda Katz</li> <li>Alan Johnson</li> <li>Charles Jolley</li> </ul>
你可以选择提供一个 else
,该代码块将只会在列表为空时显示。
{{#each paragraphs}} <p>{{this}}</p> {{else}} <p class="empty">No content</p> {{/each}}
对象迭代是可以用{{@index}}
来获取当前项的索引
template: |- <ul class="people_list"> {{#each array}} <li>{{@index}}: {{this}}</li> {{/each}} </ul> preparationScript: | // Handlebars.registerHelper('loud', function(string) { // return string.toUpperCase() // }); input: array: - Yehuda Katz - Alan Johnson - Charles Jolley
//输出 <ul class="people_list"> <li>0: Yehuda Katz</li> <li>1: Alan Johnson</li> <li>2: Charles Jolley</li> </ul>
此外,对象迭代时,可以使用{{@key}}
引用当前的键名,将上述代码中{{@index}}
换成{{@key}}
,输出是一样的
with
助手代码允许你更改 template-part
的上下文表达式。
template: | {{#with person}} {{firstname}} {{lastname}} {{/with}} preparationScript: | // Handlebars.registerHelper('loud', function(string) { // return string.toUpperCase() // }); input: person: firstname: Yehuda lastname: Katz
输出:Yehuda Katz
template: |- {{#with city as | city |}} {{#with city.location as | loc |}} {{city.name}}: {{loc.north}} {{loc.east}} {{/with}} {{/with}} preparationScript: | // Handlebars.registerHelper('loud', function(string) { // return string.toUpperCase() // }); input: city: name: San Francisco summary: San Francisco is the <b>cultural center</b> of <b>Northern California</b> location: north: '37.73,' east: -122.44 population: 883305
输出: San Francisco: 37.73, -122.44
lookup
助手代码允许使用 Handlebars 变量进行动态的参数解析。
解析数组索引的值:
template: | {{#each people}} {{.}} lives in {{lookup ../cities @index}} {{/each}} preparationScript: | // Handlebars.registerHelper('loud', function(string) { // return string.toUpperCase() // }); input: people: - Nils - Yehuda cities: - Darmstadt - San Francisco
输出: Nils lives in Darmstadt
Yehuda lives in San Francisco
基于输入的数据查找对象属性:
template: | {{#each persons as | person |}} {{name}} lives in {{#with (lookup ../cities [resident-in])~}} {{name}} ({{country}}) {{/with}} {{/each}} preparationScript: | // Handlebars.registerHelper('loud', function(string) { // return string.toUpperCase() // }); input: persons: - name: Nils resident-in: darmstadt - name: Yehuda resident-in: san-francisco cities: darmstadt: name: Darmstadt country: Germany san-francisco: name: San Francisco country: USA
//输出 Nils lives in Darmstadt (Germany) Yehuda lives in San Francisco (USA)
log
助手代码允许在执行模板时记录上下文的状态。
{{log 'this is a simple log output'}}
控制台输出:this is a simple log output
它将委托给 Handlebars.logger.log
可以使用 level
参数设置日志级别。支持的值为 debug
、info
、warn
和 error
(info
是默认值)。
template: | {{log "debug logging" level="debug"}} {{log "info logging" level="info"}} {{log "info logging is the default"}} {{log "logging a warning" level="warn"}} {{log "logging an error" level="error"}} preparationScript: |- Handlebars.logger.level = 'error' console.log('Current log level: ', Handlebars.logger.level, '\n---') input: null
控制台输出:Current log level: error
---
当 Mustache 或表达式是如下情况时被调用:
Mustache 表达式不是一个已经注册的助手代码,并且
不是当前上下文的计算属性。
你可以通过注册 helperMissing
助手代码为这些情况添加自定义处理:
template: |- {{foo}} {{foo true}} {{foo 2 true}} {{#foo true}}{{/foo}} {{#foo}}{{/foo}} preparationScript: > Handlebars.registerHelper('helperMissing', function( /* dynamic arguments */) { var options = arguments[arguments.length-1]; var args = Array.prototype.slice.call(arguments, 0,arguments.length-1) return new Handlebars.SafeString("Missing: "+options.name+"("+args+")") }) input: null
//输出 Missing: foo() Missing: foo(true) Missing: foo(2,true) Missing: foo(true)
与任何自定义助手代码或块助手代码一样,该助手代码接收相同的参数和选项(hash
,name
等)。 option.name
是被调用的助手 代码的名称。
默认行为。
如果没有参数传递给 Mustache,则默认行为是不执行任何操作并忽略整个表达式或代码块
template: |- some_{{foo}}mustache some_{{#foo}}abc{{/foo}}block preparationScript: | // Handlebars.registerHelper('loud', function(string) { // return string.toUpperCase() // });
输出:some_mustache
some_block
被调用:
代码块表达式尝试调用未注册的助手代码,
但是这个助手代码的名称与当前计算上下文中的某个属性相同。
你可以通过注册一个名为 blockHelperMissing
的助手代码来处理这种情况:
template: |- {{#person}} {{firstname}} {{lastname}} {{/person}} preparationScript: | Handlebars.registerHelper('blockHelperMissing', function(context, options) { return "Helper '"+options.name+"' not found. " + "Printing block: " + options.fn(context); }); input: person: firstname: Yehuda lastname: Katz
输出:Helper 'person' not found. Printing block: Yehuda Katz
默认行为
钩子将在当前上下文中使用已解析的属性值作为参数进行调用,并且将 options.name
字段设置为属性的名称。
如果钩子没有被覆盖,则默认实现将模仿 Mustache 的行为:只调用代码块。