写在开头的话:
在使用Ghost搭建自己的博客的时候,发现不会Handlebars.js寸步难行,所以本人决定学习下Handlebars.js,因此在此做个记录
为什么选择Handlebars.js
这里就直接引用别的博客内容了,写的还是非常不错的;地址是如下点我有惊喜哟
Handlebars.js的语法
<div>{{ content goes here }} </div>
customerName变量在Handlebars编译函数运行时被插值:
<div> Name: {{ customerName }} </div>
注释
下面的代码表明了怎样在Handlebars模板中添加注释:
{{! 在这其中的注释表达式不会被输出 }}
你也可使使用一般的HTML注释,但是它们会被输出到HTML页面源文件中,就像一般的HTML注释一样:
<!-- Regular HTML comments will be in the output -->
块表达式
块表达式在Handlebars中由一个代码块,一个开标志{{#}},一个闭合标志{{/}}组成。
我们在后面会更详细的讲解块表达式;这里是块表达式的语法:
{{#each}} Content goes here. {{/each}}
这里是一个if块表达式
{{#if someValueIsTrue}} Content goes here {{/if}}
块表达式与辅助函数有时可以互换使用因为很多内建的辅助函数都是块表达式,尽管存在函数-辅助函数(function helper)以及块辅助函数。
路径(使用点标记)
Handlebars中一个路径代表一个属性查询。如果我们在一个对象中包含name属性,例如:
var objData = {name: {firstName: "Michael", lastName:"Jackson"}}
我们可以使用嵌套路径(点标记)来查询你想要的属性,例如:
{{name.firstName}}
父路径 ../
Handlebars可以使用../来查询当前上下文中的父路径的属性。比如,有一个数据对象如下:
var shoesData = {groupName:"Celebrities", users:[{name:{firstName:"Mike", lastName:"Alexander" }}, {name:{firstName:"John", lastName:"Waters" }} ]};
? ?我们可以使用父路径 ../ 来得到groupName属性:
<script id="shoe-template" type="x-handlebars-template">
{{#users}}
<li>{{name.firstName}} {{name.lastName}} is in the {{../groupName}} group.</li>
{{/users}}
</script>
渲染以后的HTML将会是:
Mike Alexander is in the Celebrities group.
John Waters is in the Celebrities group.
上下文
Handlebars将你传递给函数的对象作为上下文。在本文中,我们使用“对象数据”或者“对象”或者“数据”来指明上下文对象。这些词有时可以互换使用,但是你只需要记住它们指的都是传递给Handlebars函数的对象。
三花括号{{{ }}}表示不转义的HTML
一般情况下,你在表达式中使用双花括号,默认的,在标准双花括号中的内容都会被转义已达到“保护你免遭由恶意数据引起的跨域攻击”的目的。这确保了 HTML中的恶意代码不会被注入到页面中。但是有时你想要原始的(未经转义的)HTML代码。此时,你可以使用Handlebars的三花括号{{{ }}},三花括号表示Handlebars不会将包含在其中的HTML内容转义。
局部模板
有时你需要在一个大模板中渲染一部分的模板。你可以使用局部模板,下面是局部模板的表达式:
{{> 局部模板名字 }}
现在来在前面的Handlebars项目中添加一个局部模板。我们将在每双鞋下面添加color和size属性。
改变main.js
1.用下面的代码替换原来的数据对象(我们提那家了color和size属性):
var shoesData = {allShoes:[{name:"Nike", price:199.00, color:"black", size:10 }, {name:"Loafers", price:59.00, color:"blue", size:9 }, {name:"Wing Tip", price:259.00, color:"brown", size:11 }]};
2.将下面的代码添加到jQuery append方法的前面:
Handlebars.registerPartial("description", $("#shoe-description").html());
改变index.html:
1.用下面的代码替换shoe-template模板:
<script id="shoe-template" type="x-handlebars-template">
{{#each allShoes}}
<li class="shoes">
<span class="shoe-name"> {{name}} - </span> price: {{price}}
{{> description}}
</li>
{{/each}}
???2.添加新的模板;在shoe-template 模板下面添加:
<script id="shoe-description" type="x-handlebars-template">
<ul>
<li>{{color}}</li>
<li>{{size}}</li>
</ul>
</script>
最终的HTML将会在每双鞋下面显示color以及size。
这就是一个将局部模板添加到主模板的例子。
Handlebars.js内建辅助函数(条件和循环)
正如在前面学到的,Handlebars是一个缺少逻辑(在模板中基本没有嵌套逻辑)模板引擎。但是有时我们必须使用复杂逻辑。Handlebars为我们提供了一个叫做辅助函数的功能,其中包含条件和循环的简单逻辑。
在HTML页面中存在逻辑表达式和逻辑块。你可以为你自定义的辅助函数提那家复杂的功能,我们在下面会进行一些讨论。
内建辅助函数
内建辅助函数(条件和循环)有:
each辅助函数:{{#each}}
我们在前面已经看到了each辅助函数。它允许你对一个数据对象(上下文)中的数组或对象进行迭代。例如,如果你拥有一个想要列在页面汇总的数组,代码如下所示:
首先设置数据
var favoriteFruits = {allFruits:["Tangerine", "Mango", "Banana"]};
??接着在script标签中使用each块
注意到这里的this指向allFruits属性 -- 在它数组中的每一个项目
?
输出的结果是下面的HTML代码:
?
- Tangerine
- Mango
- Banana
?
另外,如果传递给辅助函数的数据对象不是一个数组,那么整个对象就是当前的上下文,我们可以使用this来指代。This表示:
如果数据看起来如下所示:
?var favoriteFruits = {firstName:"Peter", lastName:"Paul"};
?或者如下所示:
??var favoriteFruits = {customers: {firstName:"Peter", lastName:"Paul"}};
??我们在这里使用this关键字来进行演示:
?既然来自数据的表达式仅仅只是对象,我们可以使用this关键字:
? {{#each this}}
- {{firstName}} {{lastName}}
{{/each}}
-- each辅助函数中的嵌套属性
我们可以在each辅助函数中使用嵌套属性(我们之前学过的):
var favoriteFruits = {allFruits:[{fruitName:"Tangerine", naitiveTo:[{country:"Venezuela"}]},{fruitName:"Mango"}] };
{{#each allFruits}}
<li>{{fruitName}} {{naitiveTo.0.country}} </li>
{{/each}}
if辅助函数:{{#if}}
if辅助函数看起来就像是一般的if语句,但是它不接收任何的条件逻辑。它检查真值例如true,任何飞空或者非null值,等等。如果if检测到真值那么块表达式将会被渲染。
--下面是一些例子:
我们检查userActive属性是否为真值,如果是,那么块表达式将会被渲染:
<div class="user-data">
{{#if userActive}}
Welcome, {{firstName}}
{{/if}}
</div>
正如一个Handlebars开发者建议的:最好检查一下值的length属性,乙方一个数组可能会是空数组:
<div class="user-data">
{{#if userActive.length}}
Welcome, {{firstName}}
{{/if}}
</div>
正如上面所说的,if辅助函数并不接收条件逻辑,因此我们不能这样写代码:
<div class="user-score">
{{#if userScore > 10 }}
Congratulations, {{firstName}}, You did it.
{{/if}}
</div>
我们必须使用一个自定义辅助函数(会在后面简短讨论)来添加一个这样的条件逻辑。
Else:{{else}}
else块(注意到它自己并不是一个块)更加简单,既然它是一个块的一部分。它可以和if块或者其他块表达式一起使用。只有当if表达式检查为假值的时候else块中的内容才会被渲染。
我们检查看userLogdedIn属性是否为真值。如果不是,else块中的内容将会被渲染:
<div class="user-data">
{{#if userLoggedIn}}
Welcome, {{firstName}}
{{else}}
Please Log in.
{{/if}}
</div>
unless辅助函数:{{#unless}}
作为else辅助函数的替代,你可以使用unless块辅助函数。unless块中的内容只有在unless检测到一个假值时才会被渲染。因此当你只想要检查一个假值时它非常有用:
我们将上面的if块和else块用unless块进行替代,当且仅当属性被检查为假值时其中的内容才会被渲染。
下面的表达式表示:只有当userLoggedIn属性被检查为假值是其中的内容才会被渲染:
{{#unless userLoggedIn}} Please Log in. {{/unless}}?
with辅助函数:{{#with}}
with辅助函数允许我们定位对象中一个特定的属性。例如,我们知道在Handlebars模板中对象总是表示当前上下文,正如我们在前面的部分中 学到的那样。但是如果你想要在当前上下文中定位一个完全不同的属性,你可以使用with辅助函数,你也可以使用父路劲(../)来完成这项工作。现在来看 看with辅助函数的具体用法:
如果我们有一个这样的上下文对象:
var shoesData = {groupName:"Celebrities", celebrity:{firstName:"Mike", lastName:"Alexander" } };??我们可以使用with块去定位我们需要的celebrity属性:
<script id="shoe-template" type="x-handlebars-template">
{{groupName}} Group
{{#with celebrity}}
<li>{{firstName}} {{lastName}}</li>
{{/with}}
</script>
渲染后的HTML如下所示:
Celebrities Group
– Mike Alexander
一般来说你几乎不会用到with块表达式。
Handlebars.js自定义辅助函数
(非常重要且功能多样)
除了我们在前面讨论过的内建辅助函数,Handlebars允许我们添加我们自己的自定义辅助函数,这甚至比内建辅助函数还要重要,因为我们可以添加任意复杂的逻辑到自定义辅助函数中。我们甚至可以用自定义函数重写内建辅助函数,尽管这有点浪费时间。
有了自定义辅助函数,我们可以添加任意的Javascript逻辑。我们需要在所有的Handlebars JS代码之前注册自定义辅助函数。自定义辅助函数在Javascript代码中被创建,而不是在Handlebars模板中。
你可以创建两种累心高的自定义辅助函数:自定义函数辅助函数(function helper),它不要要使用块表达式就能运行,自定义块辅助函数,它需要和一个块表达式一起运行。
自定义函数辅助函数(function helper)
我们来创建一个简单的自定义函数辅助函数来执行一些条件逻辑,因为我们在内建辅助函数中不能使用条件逻辑。
数据对象:
var contextObj = {score:85, userName:"Mike"};
首先,我们必须用Handlebars.registerHelper方法注册一个自定义辅助函数。这个方法接收一个字符串(辅助函数的名字)作为第一个参数,一个具有任意参数个数的函数作为第二个参数。
Handlebars.registerHelper ("theNameOfTheHelper", function (theScore) {
console.log("Grade: " + theScore );
var userGrade = "C";
if (theScore >= 90) {
return "A" ;
}
else if (theScore >= 80 && theScore < 90) {
return "B" ;
}
else if (theScore >= 70 && theScore < 80) {
return "C" ;
}
else {
return "D" ;
}
});
下面是一个使用我们刚才创建的自定义函数辅助函数的Handlebars模板:
<script id="shoe-template" type="x-handlebars-template">
{{theNameOfTheHelper score}}
</script>
HTML页面上的输出是:
B
自定义块辅助函数
除了自定义函数辅助函数,我们还可以添加自定义块辅助函数。当我们注册了一个自定义块辅助函数时,Handlebars自动在回调函数中添加了一个可选择对象作为最后一个参数。这个可选择对象拥有一个fn方法,一个hash对象,以及一个inverse方法。
options.fn方法:
fn方法接收一个对象(你的数据)作为它在自定义辅助函数块模板中作为上下文来使用的参数。你可以传递任何数据对象,或者如果你想使用引用模板的同样的上下文,你可以使用this。
下面用一个例子来说明。我们将使用一个包含得分数据的数组(最后会把所有的得分加起来):
var contextObj = [{firstName: "Kapil", lastName:"Manish", score:[22, 34, 45, 67]}, {firstName: "Bruce", lastName:"Kasparov", score:[10, 34, 67, 90]}];
在这里我们用userScore块辅助函数设定了模板,定义如下所示:
<script id="shoe-template" type="x-handlebars-template">
{{#userScore this}}
<div>{{firstName}} {{lastName}}, Your Total Score is <strong>{{score}}</strong> </div>
{{/userScore}}
</script>
我们使用Handlebars.registerHelper返回发注册userScore块辅助函数。注意到参数中的最后一个项目是可选择对象,它由Handlebars自动添加,我们在此像下面代码一样来使用它:
Handlebars.registerHelper ("userScore", function (dataObject, options) {
var templateWithInterpolatedData = "";
for (var i = dataObject.length - 1; i >= 0; i--) {
//Sum user scores from the score array and replace the array with the total
dataObject[i].score = dataObject[i].score.reduce(function (prev, cur, index, array) {
return prev + cur;
});
//每一个数据对象数组中的对象使用options.fn来进行插值,它将处理模板中所有的HTML并将来自对象中的值插入到相应位置。
//这样一来你就可以理解options.fn方法的用途了:它做的实际上就是当我们将数据对象传递给函数时普通HandlebarsMibang对象所做的工作,它好从对象中提取值并将它们插入到模板里面的HTML中
//如果在这个例子中没有options.fn对象,原始对象(而不是被插值的值)将会被返回
templateWithInterpolatedData += options.fn (dataObject[i]);
}
//我们返回拥有所有数据对象插值的完整HTML字符串
return templateWithInterpolatedData;
});
HTML的输出结果是:
?Bruce Kasparov, Your Total Score is 201
Kapil Manish, Your Total Score is 168
--非常重要的一点是知道块赋值函数可以被插值到模板的任意位置,我们也可以给自定义块辅助函数传递任意多个模板中的参数。
options.inverse方法:
inverse方法在任意块表达式总被当做else部分来使用。因此,当回调函数中的表达式为一个真值是你可以使用options.fn来返回。但是当回调函数中的表达式为假值时你可以使用options.inverse(去渲染else部分中的内容)。
options.hash对象:
Handlebars表达式不接收任何字符串和变量作为参数,但是你依然可以传递用空格分开的键-值对。例如:
(注意到这里没有逗号来分开键-值对变量)
{{#myNewHelper score=30 firstName="Jhonny" lastName="Marco"}}
Show your HTML content here.
{{/myNewHelper}}
调用拥有键-值对作为参数的Handlebars表达式将会自动添加到辅助函数回调函数的hash对象上。因此:
Handlebars.registerHelper ("myNewHelper", function (dataObject, options) {
//JSON.stringify用于序列化一个对象(为一个字符串)
console.log(JSON.stringify (options.hash));
//输出结果为:{score:30, firstName:"Jhonny", lastName:"Marco"}
});