Handlebars.js模板引擎是我们常用到的模板引擎,它是 JavaScript 一个语义模板库,通过对view和data的分离来快速构建web模板。它采用”Logic-less template”(无逻辑模版)的思路,在加载时被预编译,而不是到了客户端执行到代码时再去编译,这样可以保证模板加载和运行的速度。Handlebars兼容Mustache,你可以在Handlebars中导入Mustache模板。
本文对它的一些实用方法做了一些简单的总结,希望你在这里可以找到想用的方法。
使用与安装
Handlebars的安装非常简单,你只需要从Github下载最新版本,你也可访问下面网址获取最新信息:http://handlebarsjs.com。
目前handlebars.js已经被许多项目广泛使用了,handlebars是一个纯JS库,因此你可以像使用其他JS脚本一样用script标签来包含handlebars.js
1
| <script type="text/javascript" src=".js/handlebars.js"></script>
|
基本语法
先来段实例看看
1 2 3 4 5 6 7 8 9 10 11
| //html片段 <div id='demo'></div> <script id="demo-template" type="text/x-handlebars-template"> <p>{{title}}</p> </script> //js片段 (这里以jquery的写法为例) //预编译模板 var template = Handlebars.compile($("#demo-template").html()); //输入模板(data为需要渲染的数据,如:{"text":"Hello World!"}) $("#demo").html(template(data));
|
handlebars 表达式
Handlebars expressions是handlebars模板中最基本的单元,使用方法是加两个大括号{{ expression }}, handlebars模板会自动匹配相应的数值,对象甚至是函数。
上例中{{ title }}表示在上下文中找title
属性,获取它的值。
点分割表达式
1
| <h1>{{article.title}}</h1>
|
当前上下文找article
属性,再找它的title
属性
不转义表达式
1
| {{{<p>Hello World!</P>}}}
|
当有些内容不想被转义时,需要使用3个大括号包{{{起来。
Handlebar的表达式
Block表达式
有时候当你需要对某条表达式进行更深入的操作时,Blocks就派上用场了,在Handlebars中,你可以在表达式后面跟随一个#号来表示Blocks,然后通过{{ 表达式 }}来结束Blocks。 如果当前的表达式是一个数组,则Handlebars会“自动展开数组”,并将Blocks的上下文设为数组中的元素。 例如:
1 2 3 4 5
| <ul> {{#programme}} <li>{{language}}</li> {{/programme}} </ul>
|
有以下json数据
1 2 3 4 5 6 7
| { programme: [ {language: "JavaScript"}, {language: "HTML"}, {language: "CSS"} ] }
|
编译模板代码会自动匹配programme
数据并展开数据,渲染DOM后就是这样的
1 2 3 4 5
| <ul> <li>JavaScript</li> <li>HTML</li> <li>CSS</li> </ul>
|
Handlebars的内置块表达式(Block helper)
1.each block helper
你可以使用内置的{{ each }} helper遍历列表块内容,用this
来引用遍历的元素 例如:
1 2 3 4 5
| <ul> {{#each name}} <li>{{this}}</li> {{/each}} </ul>
|
对应适用的json数据
1 2 3
| { name: ["html","css","javascript"] }
|
这里的this
指的是数组里的每一项元素,和上面的Block很像,但原理是不一样的这里的name
是数组,而内置的each
就是为了遍历数组用的,更复杂的数据也同样适用。
通过
可以引用当前的循环索引
1 2 3
| {{ {{@index}}: {{this}} {{/each}}
|
用
可以引用当前的键名
1 2 3
| {{ {{@key}}: {{this}} {{/each}}
|
数组迭代的第一步和最后一步用 @first
和 @last
变量表示, 对象迭代时仅 @first
可用。
2.with block helper
{{ #with }}命令可以让当前的上下文进入到一个属性中,这个方法在操作复杂的template时候非常有用。
1 2 3 4 5 6
| <div class="entry"> <h1>{{title}}</h1> {{#with author}} <h2>By {{firstName}} {{lastName}}</h2> {{/with}} </div>
|
对应适用json数据
1 2 3 4 5 6 7
| { title: "My first post!", author: { firstName: "Charles", lastName: "Jolley" } }
|
渲染DOM后
1 2 3 4
| <div class="entry"> <h1>My first post!</h1> <h2>By Charles Jolley</h2> </div>
|
with-进入到某个属性(进入到某个上下文环境):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| html片段 <table> <thead> <tr> <th>姓名</th> <th>性别</th> <th>年龄</th> <th>兴趣爱好</th> </tr> </thead> <tbody id="tableList"> </tbody> <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> </table>
|
对应适用json数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| { "name": "张三", "sex": "0", "age": 18, "favorite": [ { "name":"唱歌" },{ "name":"篮球" } ] }, { "name": "李四", "sex": "0", "age": 22, "favorite": [ { "name":"上网" },{ "name":"足球" } ] }
|
with-终极this应用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| html片段 <table> <thead> <tr> <th>姓名</th> <th>性别</th> <th>年龄</th> <th>兴趣爱好</th> </tr> </thead> <tbody id="tableList"> </tbody> <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> </table>
|
对应适用json数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| { "name": "张三", "sex": "0", "age": 18, "favorite": [ "唱歌", "篮球" ] }, { "name": "李四", "sex": "0", "age": 22, "favorite": [ "上网", "足球" ] }
|
3.if else block helper
{{ #if }}就你使用JavaScript一样,你可以指定条件渲染DOM,如果它的参数返回false,undefined, null, “” 或者 [] (a “falsy” value), Handlebar将不会渲染DOM,如果存在{{ else }}则执行{{ else }}后面的渲染
例如:
1 2 3 4 5 6 7 8 9
| {{#if list}} <ul id="list"> {{#each list}} <li>{{this}}</li> {{/each}} </ul> {{else}} <p>{{error}}</p> {{/if}}
|
对应适用json数据
1 2 3 4
| var data = { info:['HTML5','CSS3',"WebGL"], "error":"数据取出错误" }
|
这里{{ #if }}判断是否存在list
数组,如果存在则遍历list
,如果不存在输出错误信息。
4.unless block helper
{{ unless }}这个语法是反向的if
语法也就是当判断的值为false
时他会渲染DOM 例如:
1 2 3 4 5 6 7 8 9
| {{#unless data}} <ul id="list"> {{#each list}} <li>{{this}}</li> {{/each}} </ul> {{else}} <p>{{error}}</p> {{/unless}}
|
Handlebars的访问(Path)
Handlebar支持路径和mustache,Handlebar还支持嵌套的路径,使得能够查找嵌套低于当前上下文的属性可以通过.
来访问属性,也可以使用../
,来访问父级属性。 例如:(使用.
访问的例子)
对应json数据
1 2 3 4 5 6 7 8
| { title: "My First Blog Post!", author: { id: 47, name: "Yehuda Katz" }, body: "My first post. Wheeeee!" }
|
例如:(使用../
访问)
1 2 3
| {{#with person}} <h1>{{../company.name}}</h1> {{/with}}
|
对应适用json数据
1 2 3 4 5 6
| { "person": { "name": "Alan" }, company: {"name": "Rad, Inc." } }
|
自定义helper
很多时候,我们需要更加复杂的if
判断逻辑,显然默认的if
不能满足我们的需求。这时你可以使用Handlebars.registerHelper()方法来注册一个helper
。
先看一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| html片段 <script id="table-template" type="text/x-handlebars-template"> {{#each student}} {{#if name}} {{#compare age 20}} <tr> <td>{{name}}</td> <td>{{transformat sex}}</td> <td>{{age}}</td> </tr> {{else}} <tr> <td>?</td> <td>?</td> <td>?</td> </tr> {{/compare}} {{/if}} {{/each}} </script> js片段: //注册一个比较大小的Helper,判断v1是否大于v2 Handlebars.registerHelper("compare",function(v1,v2,options){ if(v1>v2){ //满足添加继续执行 return options.fn(this); }else{ //不满足条件执行{{else}}部分 return options.inverse(this); } }); //注册一个翻译用的Helper,0翻译成男,1翻译成女 Handlebars.registerHelper("transformat",function(value){ if(value==0){ return "男"; }else if(value==1){ return "女"; } }); json数据: { "student": [ { "name": "张三", "sex": "0", "age": 23 }, { "sex": "0", "age": 22 }, { "name": "妞妞", "sex": "1", "age": 18 } ] }
|
本例中,利用Handlebars.js中Helper强大的扩展性,定义了一个compare
,它用来比较两个数的大小,如果第一个数大于第二个数,满足条件继续执行,否则执行{{ else }}部分。
Handlebars.registerHelper用来定义Helper,它有两个参数,第一个参数是Helper名称,第二个参数是一个回调函数,用来执行核心业务逻辑。本例中的函数,有三个参数,其中前两个参数是需要比较的两个数,第三个参数是固定的,就叫options
,如果加了该参数,就说明这个Helper是一个Block,块级别的Helper,有一定的语法结构,调用的时候加#号,就像if
那样。
关于options
的使用,我所了解的就是这种用法,return options.fn(this);
表示满足条件继续执行,也就是执行{{# compare }}和{{ else }}之间的代码;return options.inverse(this);
表示不满足条件,也就是执行{{ else }}和{{ /compare }}之间的代码。
由于这是一个块级别的Helper,所以调用要加#,例如:{{ #compare age 20 }},其中的age就是当前上下文中读取到的年龄,20是我随便写的值,意思是只要age比20大,就显示,否则全显示?。
可以看出,Helper中写的可以是任何js代码,现在想想,就知道Handlebars有多灵活了吧!!
上面注册的两个Helper,一个带options参数,另一个不带;带options参数的Helper是块级别的,而不带的,相当于行内级别的Helper。
从例子一开始,性别就是用0、1代码表示的,但实际情况下我们需要转换成汉字,transformat
这个Helper需要一个参数,根据不同的代码,返回男女,这样调用{{ transformat sex }},其中sex是从当前上下文中读取的性别代码。
内建工具
转义字符串
1
| Handlebars.Utils.escapeExpression(string)
|
判断空值
1
| Handlebars.Utils.isEmpty(value)
|
扩展对象
1
| Handlebars.Utils.extend(foo, {bar: true})
|
转字符串
1
| Handlebars.Utils.toString(obj)
|
判断数组
1
| Handlebars.Utils.isArray(obj)
|
判断函数
1
| Handlebars.Utils.isFunction(obj)
|