handlebars不算什么新技术,但是确实是一款非常好用的模版引擎,初次使用,这里做一下总结,对于不认这个东西朋友们,他是个什么东西呢?
这里我就说一个我们经常遇到的情况,在系统开发的过程中,我们经常要写异步请求,然后拿到json数据,之后在js中写一大坨html代码拼接上json数据,然后通过jquery的方法动态加载到页面上。
上面说的情况作为程序员大家肯定都遇到过也都做过,其中的痛苦之处大家都懂,尤其是有错误回来检查的时候,看着那一大坨代码真心恶心,那么handlebars就是来解决这个问题的。
他首先可以在页面上定义一个html代码的模版,然后,经过很简单步骤就可以实现上述效果了,而且修改起来so esay! look code!
1.首先需要引入这两个js包,因为handlebars也是基于jquery的,jquery的强大之处毋庸置疑。
<script type="text/javascript" src="script/jquery.js"></script>
<script type="text/javascript" src="script/handlebars-1.0.0.beta.6.js"></script>
2.定义一个模版,并且准备引擎处理完的代码放到哪里,这里定义一个巨简单的模版方便理解
<%-- Handlebars处理完的代码放到这个div中 --%>
<div id="description"></div>
<%-- Handlebars.js模版 --%>
<%-- Handlebars.js模版放在script标签中,保留了html原有层次结构,模版中要写一些操作语句 --%>
<%-- id可以用来唯一确定一个模版,type是模版固定的写法 --%>
<script id="description-template" type="text/x-handlebars-template">
<table>
{{#each userList}}
<tr>
<td>{{username}}</td>
<td>{{password}}</td>
</tr>
{{/each}}
</table>
</script>
3.下面是js调用模版进行一些处理的代码
<script>
$(window).load(function() {
var config = {
"url" : "/user/userList.json",// json请求的地址
"params" : {// json请求的参数信息, 没有的话可以不设置这个属性,或者是 {}空对象
"shopId" : 1
},
"renderTemplateSelector" : "#description-template",// 模板
"renderToSelector" : "#description",// 你要把处理后的代码设置到哪个元素中
"beforeRenderjsonDataEvent" : function(jsonData) {// 渲染handlebars数据之前 做了什么
// TODO
},
"afterRenderjsonDataEvent" : function(jsonData) {// 渲染handlebars数据之后 做了什么
// TODO
}
"parseRenderjsonData" : function(jsonData) {// 渲染handlebars需要的数据,此处 jsonData是从后端返回的json数据
return {
"userList" : jsonData // 注意这里的userList与你模版中用的userList是同一个东西,当然这里可以return多个值,以应对不同的需求,在模版中都可以通过userList同样的方式去使用。
};
}
};
loadJsonAndRenderTemplateHtmlToSelector(config);
});
// 这个方法是封装过的方法以便实现更多功能,比如渲染前需要执行什么方法,渲染后需要执行什么,稍微看下就能看懂的
function loadJsonAndRenderTemplateHtmlToSelector(config) {
// 执行ajax请求
$.post(config.url, config.params, {
success : function(jsonData) {
// 判断ajax返回的数据有没有问题
if (null != jsonData && "" != jsonData && !$.isEmptyObject(jsonData)) {
console.log("return jsonData:%o", jsonData);
var canRender = true;
// 渲染handlebars数据之前 做了什么
if ($.isFunction(config.beforeRenderjsonDataEvent)) {
// 渲染前,调用该方法,该方法可以通过返回true或者false来决定是否继续渲染
canRender = config.beforeRenderjsonDataEvent(jsonData);
}
// 支持在 beforeRenderjsonDataEvent 返回是否可以渲染
if (!canRender) {
return;
}
// 渲染
var commentTemplate = Handlebars.compile($(config.renderTemplateSelector).html());
renderTemplateHtmlToSelector(config.renderToSelector, config.parseRenderjsonData(jsonData), commentTemplate);
// 渲染handlebars数据之后 做点什么
if ($.isFunction(config.afterRenderjsonDataEvent)) {
config.afterRenderjsonDataEvent(jsonData);
}
} else {
console.warn("[%o] jsonData is null or empty,nothing to do!!!", config.renderToSelector);
}
}
}, {
error : function(jsonData) {
console.log(jsonData);
}
});
}
/**
* 渲染 handlebarsTemplate
*
* @param selector
* 要渲染的选择器
* @param data
* 数据 数据格式 { "title" : "xxxx", "recommendationEngineCommandList" : xxxx }
*
* @param template
* 模板
*/
function renderTemplateHtmlToSelector(selector, data, template) {
var html = template(data);
console.log("selector:%o,html:%o", selector, html);
// 将json对象用刚刚注册的Handlebars模版封装,得到最终的html,插入到基础table中。
$(selector).html(html);
}
</script>
至此,handlebars的基本功能和应用场景大家应该能够理解了。
4.扩展一些handlebars模版中常用到的操作
// 其实handlebars中比较好用的方法不多,他提倡的是自己写方法实现,但还是介绍下我较常用的。
// 如果XXX不是对象而是数组的话,可以直接下面的用法,如果是对象的话,上面的例子已经介绍过了使用方法。
{{#each XXX}} <li>{{this}}</li> {{each}}
// 如果XXX是map的话,可以这样用,@key得到的key的值,this得到的是该key的value
{{#each XXX}} <li>{{@key}}</li><li>{{this}}</li> {{each}}
// 但凡使用each循环的,那么都可以通过@index得到当前循环的下标
{{@index}}
// handlebars本身是带有if方法的,但是并不推荐用,他的if并不能进行比较,只能判断是否存在,或者true和false,至少我现在是这么理解的,如下
{{#if XXX}}
{{else}}
{{/if}}
// 我们一般需求都会比较复杂,所以这里推荐自己注册方法来实现需求,handlebars专门提供了registerHelper用来进行方法的注册,那么如何注册呢,看下面代码。
<script>
// 一个判断字符串是否相等的方法equals
Handlebars.registerHelper("equals",function(v1, v2, options){
if (v1 == v2) {
return options.fn(this);// 满足添加继续执行
}
return options.inverse(this);// 不满足条件执行{{else}}部分
});
// 这是用来比较大小的
Handlebars.registerHelper("isBig",function(big,small,options){
if(big > small){
return options.fn(this);// 满足添加继续执行
}
return options.inverse(this);// 不满足条件执行{{else}}部分
});
// 这是截取字符串的方法
Handlebars.registerHelper("substring",function(str, start, end) {
if(str==null || str=="") {
return str;
}
return str.substring(start,end);
});
</script>
以上三个方法,应用于模版中的代码如下
// 比较"aa"和"bb"是否相等
{{#equals "aa" "bb"}}
{{else}}
{{/equals}}
// 比较3是否大于2
{{#isBig 3 2}}
{{else}}
{{/isBig}}
// 截取abcdefg字符串
{{substring "abcdefg" 2 5}}
注意以上的几种使用方式,可以看出,判断true和false的和有return值的写法上不太一样,前者需要“#”后者则不需要。
这里说另一种情况,each嵌套的问题,如果要取上一层的对象的属性值,使用../加属性名
<script id="table-template" type="text/x-handlebars-template">
{{#each this}}
{{#each info}}
{{../name}}的{{this}}<br>
{{/each}}
{{/each}}
</script>
至此我所了解的handlebars功能基本介绍完毕,如果有新的应用我会及时更新,也请大家多多指教。