Handlebars 是 JavaScript 一个语义模板库,通过对view和data的分离来快速构建Web模板。利用Handlebars处理HTML模板时,一般步骤如下:
1. 获取模板内容
2. 预编译模板
3. 模板数据填充
4. 将结果追加到页面中
下图是html模板被渲染后的结果:
有两种方式来实现这个小小的demo
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>demo2</title>
<script type="text/javascript" src="./jquery.js"></script>
<script type="text/javascript" src="handlebars.js"></script>
</head>
<body>
<div class="demo">
<div class="tpldemo">
<h1 style="color:{{color}}">{{demo1}}</h1>
<p>{{desc}}</p>
</div>
</div>
<script type="text/javascript">
var context = {
"demo1": "this is a demo",
"desc": "study Handlebars",
"color": "red"
};
//1. 获取模板内容
var tpl = $(".tpldemo").html();
//2. 预编译模板
var template = Handlebars.compile(tpl);
//3. 模板数据填充
var html = template(context);
//4. 将结果追加到页面中
$(".tpldemo").html(html);
</script>
</body>
</html>
2.借用 <script>
标签
<div class="demo">
<script id="tpl" type="text/x-handlebars-template">
<div class="tpldemo">
<h1 style="color:{{color}}">{{demo1}}</h1>
<p>{{desc}}</p>
</div>
</script>
</div>
<script type="text/javascript">
var context = {
"demo1": "this is a demo",
"desc": "study Handlebars",
"color": "red"
};
//1. 获取模板内容
var tpl = $("#tpl").html();
//2. 预编译模板
var template = Handlebars.compile(tpl);
//3. 模板数据填充
var html = template(context);
//4. 将结果追加到页面中
$(".demo").html(html);
</script>
需要注意的是,数据名要保持一致,即 {{name}}
中的 name
要和 context
提供的名称保持一致。
echo
指令可以用于循环json数据对象的属性
//引入插件
<script type="text/javascript" src="./jquery.js"></script>
<script type="text/javascript" src="handlebars.js"></script>
//模板
<script id="table-template" type="text/x-handlebars-template">
{{#each student}}
<tr>
<td>{{name}}</td>
<td>{{sex}}</td>
<td>{{age}}</td>
</tr>
{{/each}}
</script>
//数据处理
<script type="text/javascript">
$(document).ready(function() {
//模拟的json对象
var data = {
"student": [
{
"name": "张三",
"sex": "0",
"age": 18
},
{
"name": "李四",
"sex": "0",
"age": 22
},
{
"name": "妞妞",
"sex": "1",
"age": 18
}
]
};
//注册一个Handlebars模版,通过id找到某一个模版,获取模版的html框架
var myTemplate = Handlebars.compile($("#table-template").html());
//将json对象用刚刚注册的Handlebars模版封装,得到最终的html,插入到基础table中。
$('#tableList').html(myTemplate(data));
});
</script>
with
指令可以转移上下文环境,让当前的上下文进入到一个属性中。
//引入插件
<script type="text/javascript" src="./jquery.js"></script>
<script type="text/javascript" src="handlebars.js"></script>
//模板
<script id="table-template" type="text/x-handlebars-template">
{{#each this}}
<tr>
<td>{{name}}</td>
<td>{{sex}}</td>
<td>{{age}}</td>
<td>
{{#with favorite}}
{{#each this}}
<p>{{name}}</p>
{{/each}}
{{/with}}
</td>
</tr>
{{/each}}
</script>
//数据处理
//模拟的json对象
var data = [
{
"name": "张三",
"sex": "0",
"age": 18,
"favorite":
[
{
"name":"唱歌"
},{
"name":"篮球"
}
]
},
{
"name": "李四",
"sex": "0",
"age": 22,
"favorite":
[
{
"name":"上网"
},{
"name":"足球"
}
]
},
];
//注册一个Handlebars模版,通过id找到某一个模版,获取模版的html框架
var myTemplate = Handlebars.compile($("#table-template").html());
//将json对象用刚刚注册的Handlebars模版封装,得到最终的html,插入到基础table中。
$('#tableList').html(myTemplate(data));
});
{{#with favorite}}
表示进入到 favorite
属性的上下文中,而 favorite
属性中又是一个list,因此可以用 {{#each this}}
进行遍历,表示遍历当前上下文环境,对于每次遍历,都是map结构,取name属性,最终拿到所有兴趣爱好。
with
可以结合handlebars的路径访问一起使用。Handlebars提供了 .
来访问属性也可以使用 ../
来访问父级属性。
{{#with person}}
<h1>{{../company.name}}</h1>
{{/with}}
//对应的json数据
{
"person":
{ "name": "Alan" },
company:
{"name": "Rad, Inc." }
}
this
表示当前的上下文,在上述示例中已经在 with
中使用了 this
,当然,也是可以在 each
中使用的。在 with
中使用 this
还有一种方式:
<script id="table-template" type="text/x-handlebars-template">
{{#each this}}
<tr>
<td>{{name}}</td>
<td>{{sex}}</td>
<td>{{age}}</td>
<td>
{{#with favorite}}
{{#each this}}
<p>{{this}}</p>
{{/each}}
{{/with}}
</td>
</tr>
{{/each}}
</script>
//数据处理
<script type="text/javascript">
$(document).ready(function() {
//模拟的json对象
var data = [
{
"name": "张三",
"sex": "0",
"age": 18,
"favorite":
[
"唱歌",
"篮球"
]
},
{
"name": "李四",
"sex": "0",
"age": 22,
"favorite":
[
"上网",
"足球"
]
},
{
"name": "妞妞",
"sex": "1",
"age": 18,
"favorite":
[
"电影",
"旅游"
]
}
];
//注册一个Handlebars模版,通过id找到某一个模版,获取模版的html框架
var myTemplate = Handlebars.compile($("#table-template").html());
//将json对象用刚刚注册的Handlebars模版封装,得到最终的html,插入到基础table中。
$('#tableList').html(myTemplate(data));
});
</script>
本例和上例不同之处在于 favorite
属性中不再是map项,而是普通字符串,因此对于每个项,可以直接用 {{this}}
读取, this
代表当前字符串。
if
指令可以根据当前上下文是否存在来执行制定的数据处理,常配合 else
指令。
//模板
{{#if list}}
<ul id="list">
{{#each list}}
<li>{{this}}</li>
{{/each}}
</ul>
{{else}}
<p>{{error}}</p>
{{/if}}
//对应的json
var data = {
info:['HTML5','CSS3',"WebGL"],
"error":"数据取出错误"
}
这里 {{#if}}
判断是否存在 list
数组,如果存在则遍历list,如果不存在输出错误信息。
对于 if
指令,如果返回的为 undefined
、 null
、 ""
、 []
、 false
任意一个,都会导致最终结果为假。
if
指令支持嵌套,如: {{#if name.xxx}}
,这样写就假设name属性是一个map,检测name属性中是否包含xxx属性。
unless
则是和 if
指令相反,当判断的值为 false
时他会渲染DOM :
{{#unless data}}
<ul id="list">
{{#each list}}
<li>{{this}}</li>
{{/each}}
</ul>
{{else}}
<p>{{error}}</p>
{{/unless}}
对于复杂的逻辑判断, if
指令不能完成时,我们可以自定义Helper。
Handlebars.registerHelper
用来定义Helper,它有两个参数,第一个参数是Helper名称,第二个参数是一个回调函数,用来执行核心业务逻辑。
在函数级Helper,回调函数的参数就是模板传来的参数。
<script id="shoe-template" type="x-handlebars-template">
{{theNameOfTheHelper score}}
</script>
//数据处理
var contextObj = {score:85, userName:"Mike"}; //模拟的数据
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" ;
}
});
将上下文中读取到的 score
作为参数传递给回调函数,回调函数的返回结果会作为模板的填充数据。该示例最终会在html中输出B。
但是在定义块级Helper时,Handlebars会自动在回调函数的最后一个参数加上 options
对象。 options
对象有一个 fn()
、 inverse()
方法一hi两个方法以及一个 hash
对象。
The options.fn method:
The fn method takes an object (your data) as a parameter that it uses as the context inside the custom helper block template. You can pass any data object, or if you want to use the same data context referenced in the template, you can use this.
The options.inverse method:
The inverse method is used as the else section of any block statement. So, you would use options.fn to return when the expression in the callback evaluates to a truthy value. But you would use options.inverse when the expression evaluates to falsy (to render content in the else part of the block).
The options.hash object:
Handlebars expressions take not only strings and variables as arguments, but you can pass key-value pairs separated by spaces as well.
<script id="table-template" type="text/x-handlebars-template">
{{#each student}}
{{#if name}}
{{#compare age 20}}
<tr>
<td>{{name}}</td>
<td>{{sex}}</td>
<td>{{age}}</td>
</tr>
{{else}}
<tr>
<td>?</td>
<td>?</td>
<td>?</td>
</tr>
{{/compare}}
{{/if}}
{{/each}}
</script>
//数据处理
//模拟的json对象
var data = {
"student": [
{
"name": "张三",
"sex": "0",
"age": 23
},
{
"sex": "0",
"age": 22
},
{
"name": "妞妞",
"sex": "1",
"age": 18
}
]
};
//注册一个Handlebars模版,通过id找到某一个模版,获取模版的html框架
var myTemplate = Handlebars.compile($("#table-template").html());
//注册一个比较大小的Helper,判断v1是否大于v2
Handlebars.registerHelper("compare",function(v1,v2,options){
if(v1>v2){
//满足添加继续执行
return options.fn(this);
}else{
//不满足条件执行{{else}}部分
return options.inverse(this);
}
});
//将json对象用刚刚注册的Handlebars模版封装,得到最终的html,插入到基础table中。
$('#tableList').html(myTemplate(data));
其中的age就是当前上下文中读取到的年龄,20是随便写的值,意思是只要age比20大,就显示,否则全显示?。
但是如果传递给函数的是一个空格分开的键值对,则会保存包 options.hash
中。
{{#myNewHelper score=30 firstName="Jhonny" lastName="Marco"}}
Show your HTML content here.
{{/myNewHelper}}
Handlebars.registerHelper ("myNewHelper", function (dataObject, options) {
//JSON.stringify used to serialize the object (to a string)
console.log(JSON.stringify (options.hash));
//The output is: {score:30, firstName:"Jhonny", lastName:"Marco"}
});
在handlebars里, {{expression}}
会返回一个经过编码的HTML,也就是说,如果取出的内容中包含html标签,会被转码成纯文本,不会被当成html解析,实际上就是做了类似这样的操作:把 <
用 <
替代。如果需要解析html,不要转码,可以使用 {{{
。
//模板
<script id="table-template" type="text/x-handlebars-template">
{{#each student}}
<tr>
<td>{{name}}</td>
<td>{{sex}}</td>
<td>{{age}}</td>
{{#compare age 20}}
<td>{{homePage}}</td>
{{else}}
<td>{{{homePage}}}</td>
{{/compare}}
</tr>
{{/each}}
</script>
//模拟的json对象
var data = {
"student": [
{
"name": "张三",
"sex": "0",
"age": 18,
"homePage":"<a href='javascript:void(0);'>张三的个人主页</a>"
},
{
"name": "李四",
"sex": "0",
"age": 22,
"homePage":"<a href='javascript:void(0);'>李四的个人主页</a>"
},
{
"name": "妞妞",
"sex": "1",
"age": 19,
"homePage":"<a href='javascript:void(0);'>妞妞的个人主页</a>"
}
]
};
//注册一个Handlebars模版,通过id找到某一个模版,获取模版的html框架
var myTemplate = Handlebars.compile($("#table-template").html());
//注册一个比较数字大小的Helper,有options参数,块级Helper
Handlebars.registerHelper("compare",function(v1,v2,options){
//判断v1是否比v2大
if(v1>v2){
//继续执行
return options.fn(this);
}else{
//执行else部分
return options.inverse(this);
}
});
//将json对象用刚刚注册的Handlebars模版封装,得到最终的html,插入到基础table中。
$('#tableList').html(myTemplate(data));
本例中,年龄大于20的童鞋个人主页被编码,直接展示出来;而年龄小于20的童鞋,个人主页被当成html解析,显示的是一个超链接。
handlebars不会编码 Handlebars.SafeString
。如果你自定义一个helper,返回一段HTML代码,你需要返回 new Handlebars.SafeString(result)
。此时,你需要手动对内容进行编码:
Handlebars.registerHelper('link', function(text, url) {
text = Handlebars.Utils.escapeExpression(text);
url = Handlebars.Utils.escapeExpression(url);
var result = '<a href="' + url + '">' + text + '</a>';
return new Handlebars.SafeString(result);
});