Handlebars.js初探

标签: JavaScript handlebars js模板 | 发表时间:2015-08-02 15:30 | 作者:dwqs
出处:http://www.ido321.com

引言

Handlebars 是 JavaScript 一个语义模板库,通过对view和data的分离来快速构建Web模板。利用Handlebars处理HTML模板时,一般步骤如下:
1. 获取模板内容
2. 预编译模板
3. 模板数据填充
4. 将结果追加到页面中

下图是html模板被渲染后的结果:

有两种方式来实现这个小小的demo

1.直接在HTML中渲染

   
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>demo2</title>
  6. <script type="text/javascript" src="./jquery.js"></script>
  7. <script type="text/javascript" src="handlebars.js"></script>
  8. </head>
  9. <body>
  10. <div class="demo">
  11. <div class="tpldemo">
  12. <h1 style="color:{{color}}">{{demo1}}</h1>
  13. <p>{{desc}}</p>
  14. </div>
  15. </div>
  16. <script type="text/javascript">
  17. var context = {
  18. "demo1": "this is a demo",
  19. "desc": "study Handlebars",
  20. "color": "red"
  21. };
  22. //1. 获取模板内容
  23. var tpl = $(".tpldemo").html();
  24. //2. 预编译模板
  25. var template = Handlebars.compile(tpl);
  26. //3. 模板数据填充
  27. var html = template(context);
  28. //4. 将结果追加到页面中
  29. $(".tpldemo").html(html);
  30. </script>
  31. </body>
  32. </html>

2.借用 <script>标签

   
  1. <div class="demo">
  2. <script id="tpl" type="text/x-handlebars-template">
  3. <div class="tpldemo">
  4. <h1 style="color:{{color}}">{{demo1}}</h1>
  5. <p>{{desc}}</p>
  6. </div>
  7. </script>
  8. </div>
  9. <script type="text/javascript">
  10. var context = {
  11. "demo1": "this is a demo",
  12. "desc": "study Handlebars",
  13. "color": "red"
  14. };
  15. //1. 获取模板内容
  16. var tpl = $("#tpl").html();
  17. //2. 预编译模板
  18. var template = Handlebars.compile(tpl);
  19. //3. 模板数据填充
  20. var html = template(context);
  21. //4. 将结果追加到页面中
  22. $(".demo").html(html);
  23. </script>

需要注意的是,数据名要保持一致,即 {{name}}中的 name要和 context提供的名称保持一致。

基本循环:echo

echo指令可以用于循环json数据对象的属性

   
  1. //引入插件
  2. <script type="text/javascript" src="./jquery.js"></script>
  3. <script type="text/javascript" src="handlebars.js"></script>
  4. //模板
  5. <script id="table-template" type="text/x-handlebars-template">
  6. {{#each student}}
  7. <tr>
  8. <td>{{name}}</td>
  9. <td>{{sex}}</td>
  10. <td>{{age}}</td>
  11. </tr>
  12. {{/each}}
  13. </script>
  14. //数据处理
  15. <script type="text/javascript">
  16. $(document).ready(function() {
  17. //模拟的json对象
  18. var data = {
  19. "student": [
  20. {
  21. "name": "张三",
  22. "sex": "0",
  23. "age": 18
  24. },
  25. {
  26. "name": "李四",
  27. "sex": "0",
  28. "age": 22
  29. },
  30. {
  31. "name": "妞妞",
  32. "sex": "1",
  33. "age": 18
  34. }
  35. ]
  36. };
  37. //注册一个Handlebars模版,通过id找到某一个模版,获取模版的html框架
  38. var myTemplate = Handlebars.compile($("#table-template").html());
  39. //将json对象用刚刚注册的Handlebars模版封装,得到最终的html,插入到基础table中。
  40. $('#tableList').html(myTemplate(data));
  41. });
  42. </script>

指定上下文:with

with指令可以转移上下文环境,让当前的上下文进入到一个属性中。

   
  1. //引入插件
  2. <script type="text/javascript" src="./jquery.js"></script>
  3. <script type="text/javascript" src="handlebars.js"></script>
  4. //模板
  5. <script id="table-template" type="text/x-handlebars-template">
  6. {{#each this}}
  7. <tr>
  8. <td>{{name}}</td>
  9. <td>{{sex}}</td>
  10. <td>{{age}}</td>
  11. <td>
  12. {{#with favorite}}
  13. {{#each this}}
  14. <p>{{name}}</p>
  15. {{/each}}
  16. {{/with}}
  17. </td>
  18. </tr>
  19. {{/each}}
  20. </script>
  21. //数据处理
  22. //模拟的json对象
  23. var data = [
  24. {
  25. "name": "张三",
  26. "sex": "0",
  27. "age": 18,
  28. "favorite":
  29. [
  30. {
  31. "name":"唱歌"
  32. },{
  33. "name":"篮球"
  34. }
  35. ]
  36. },
  37. {
  38. "name": "李四",
  39. "sex": "0",
  40. "age": 22,
  41. "favorite":
  42. [
  43. {
  44. "name":"上网"
  45. },{
  46. "name":"足球"
  47. }
  48. ]
  49. },
  50. ];
  51. //注册一个Handlebars模版,通过id找到某一个模版,获取模版的html框架
  52. var myTemplate = Handlebars.compile($("#table-template").html());
  53. //将json对象用刚刚注册的Handlebars模版封装,得到最终的html,插入到基础table中。
  54. $('#tableList').html(myTemplate(data));
  55. });

{{#with favorite}}表示进入到 favorite属性的上下文中,而 favorite属性中又是一个list,因此可以用 {{#each this}}进行遍历,表示遍历当前上下文环境,对于每次遍历,都是map结构,取name属性,最终拿到所有兴趣爱好。

with可以结合handlebars的路径访问一起使用。Handlebars提供了 .来访问属性也可以使用 ../来访问父级属性。

   
  1. {{#with person}}
  2. <h1>{{../company.name}}</h1>
  3. {{/with}}
  4. //对应的json数据
  5. {
  6. "person":
  7. { "name": "Alan" },
  8. company:
  9. {"name": "Rad, Inc." }
  10. }

this的使用

this表示当前的上下文,在上述示例中已经在 with中使用了 this,当然,也是可以在 each中使用的。在 with中使用 this还有一种方式:

   
  1. <script id="table-template" type="text/x-handlebars-template">
  2. {{#each this}}
  3. <tr>
  4. <td>{{name}}</td>
  5. <td>{{sex}}</td>
  6. <td>{{age}}</td>
  7. <td>
  8. {{#with favorite}}
  9. {{#each this}}
  10. <p>{{this}}</p>
  11. {{/each}}
  12. {{/with}}
  13. </td>
  14. </tr>
  15. {{/each}}
  16. </script>
  17. //数据处理
  18. <script type="text/javascript">
  19. $(document).ready(function() {
  20. //模拟的json对象
  21. var data = [
  22. {
  23. "name": "张三",
  24. "sex": "0",
  25. "age": 18,
  26. "favorite":
  27. [
  28. "唱歌",
  29. "篮球"
  30. ]
  31. },
  32. {
  33. "name": "李四",
  34. "sex": "0",
  35. "age": 22,
  36. "favorite":
  37. [
  38. "上网",
  39. "足球"
  40. ]
  41. },
  42. {
  43. "name": "妞妞",
  44. "sex": "1",
  45. "age": 18,
  46. "favorite":
  47. [
  48. "电影",
  49. "旅游"
  50. ]
  51. }
  52. ];
  53. //注册一个Handlebars模版,通过id找到某一个模版,获取模版的html框架
  54. var myTemplate = Handlebars.compile($("#table-template").html());
  55. //将json对象用刚刚注册的Handlebars模版封装,得到最终的html,插入到基础table中。
  56. $('#tableList').html(myTemplate(data));
  57. });
  58. </script>

本例和上例不同之处在于 favorite属性中不再是map项,而是普通字符串,因此对于每个项,可以直接用 {{this}}读取, this代表当前字符串。

条件判断:if、unless

if指令可以根据当前上下文是否存在来执行制定的数据处理,常配合 else指令。

   
  1. //模板
  2. {{#if list}}
  3. <ul id="list">
  4. {{#each list}}
  5. <li>{{this}}</li>
  6. {{/each}}
  7. </ul>
  8. {{else}}
  9. <p>{{error}}</p>
  10. {{/if}}
  11. //对应的json
  12. var data = {
  13. info:['HTML5','CSS3',"WebGL"],
  14. "error":"数据取出错误"
  15. }

这里 {{#if}}判断是否存在 list数组,如果存在则遍历list,如果不存在输出错误信息。

对于 if指令,如果返回的为 undefinednull""[]false任意一个,都会导致最终结果为假。

if指令支持嵌套,如: {{#if name.xxx}},这样写就假设name属性是一个map,检测name属性中是否包含xxx属性。

unless则是和 if指令相反,当判断的值为 false时他会渲染DOM :

   
  1. {{#unless data}}
  2. <ul id="list">
  3. {{#each list}}
  4. <li>{{this}}</li>
  5. {{/each}}
  6. </ul>
  7. {{else}}
  8. <p>{{error}}</p>
  9. {{/unless}}

自定义Helper

对于复杂的逻辑判断, if指令不能完成时,我们可以自定义Helper。

Handlebars.registerHelper用来定义Helper,它有两个参数,第一个参数是Helper名称,第二个参数是一个回调函数,用来执行核心业务逻辑。

在函数级Helper,回调函数的参数就是模板传来的参数。

   
  1. <script id="shoe-template" type="x-handlebars-template">​
  2. {{theNameOfTheHelper score}}
  3. ​</script>
  4. //数据处理
  5. var contextObj = {score:85, userName:"Mike"}; //模拟的数据
  6. Handlebars.registerHelper ("theNameOfTheHelper", function (theScore) {
  7. console.log("Grade: " + theScore );
  8. var userGrade = "C";
  9. if (theScore >= 90) {
  10. return "A" ;
  11. }
  12. else if (theScore >= 80 && theScore < 90) {
  13. return "B" ;
  14. }
  15. else if (theScore >= 70 && theScore < 80) {
  16. return "C" ;
  17. }
  18. else {
  19. return "D" ;
  20. }
  21. });

将上下文中读取到的 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.

   
  1. <script id="table-template" type="text/x-handlebars-template">
  2. {{#each student}}
  3. {{#if name}}
  4. {{#compare age 20}}
  5. <tr>
  6. <td>{{name}}</td>
  7. <td>{{sex}}</td>
  8. <td>{{age}}</td>
  9. </tr>
  10. {{else}}
  11. <tr>
  12. <td>?</td>
  13. <td>?</td>
  14. <td>?</td>
  15. </tr>
  16. {{/compare}}
  17. {{/if}}
  18. {{/each}}
  19. </script>
  20. //数据处理
  21. //模拟的json对象
  22. var data = {
  23. "student": [
  24. {
  25. "name": "张三",
  26. "sex": "0",
  27. "age": 23
  28. },
  29. {
  30. "sex": "0",
  31. "age": 22
  32. },
  33. {
  34. "name": "妞妞",
  35. "sex": "1",
  36. "age": 18
  37. }
  38. ]
  39. };
  40. //注册一个Handlebars模版,通过id找到某一个模版,获取模版的html框架
  41. var myTemplate = Handlebars.compile($("#table-template").html());
  42. //注册一个比较大小的Helper,判断v1是否大于v2
  43. Handlebars.registerHelper("compare",function(v1,v2,options){
  44. if(v1>v2){
  45. //满足添加继续执行
  46. return options.fn(this);
  47. }else{
  48. //不满足条件执行{{else}}部分
  49. return options.inverse(this);
  50. }
  51. });
  52. //将json对象用刚刚注册的Handlebars模版封装,得到最终的html,插入到基础table中。
  53. $('#tableList').html(myTemplate(data));

其中的age就是当前上下文中读取到的年龄,20是随便写的值,意思是只要age比20大,就显示,否则全显示?。

但是如果传递给函数的是一个空格分开的键值对,则会保存包 options.hash中。

   
  1. {{#myNewHelper score=30 firstName="Jhonny" lastName="Marco"}}​
  2. Show your HTML content here.
  3. {{/myNewHelper}}
  4. Handlebars.registerHelper ("myNewHelper", function (dataObject, options) {
  5. ​//JSON.stringify used to serialize the object (to a string)​
  6. console.log(JSON.stringify (options.hash));
  7. ​//The output is: {score:30, firstName:"Jhonny", lastName:"Marco"}​
  8. });

HTML编码

在handlebars里, {{expression}}会返回一个经过编码的HTML,也就是说,如果取出的内容中包含html标签,会被转码成纯文本,不会被当成html解析,实际上就是做了类似这样的操作:把 <&lt;替代。如果需要解析html,不要转码,可以使用 {{{

   
  1. //模板
  2. <script id="table-template" type="text/x-handlebars-template">
  3. {{#each student}}
  4. <tr>
  5. <td>{{name}}</td>
  6. <td>{{sex}}</td>
  7. <td>{{age}}</td>
  8. {{#compare age 20}}
  9. <td>{{homePage}}</td>
  10. {{else}}
  11. <td>{{{homePage}}}</td>
  12. {{/compare}}
  13. </tr>
  14. {{/each}}
  15. </script>
  16. //模拟的json对象
  17. var data = {
  18. "student": [
  19. {
  20. "name": "张三",
  21. "sex": "0",
  22. "age": 18,
  23. "homePage":"<a href='javascript:void(0);'>张三的个人主页</a>"
  24. },
  25. {
  26. "name": "李四",
  27. "sex": "0",
  28. "age": 22,
  29. "homePage":"<a href='javascript:void(0);'>李四的个人主页</a>"
  30. },
  31. {
  32. "name": "妞妞",
  33. "sex": "1",
  34. "age": 19,
  35. "homePage":"<a href='javascript:void(0);'>妞妞的个人主页</a>"
  36. }
  37. ]
  38. };
  39. //注册一个Handlebars模版,通过id找到某一个模版,获取模版的html框架
  40. var myTemplate = Handlebars.compile($("#table-template").html());
  41. //注册一个比较数字大小的Helper,有options参数,块级Helper
  42. Handlebars.registerHelper("compare",function(v1,v2,options){
  43. //判断v1是否比v2大
  44. if(v1>v2){
  45. //继续执行
  46. return options.fn(this);
  47. }else{
  48. //执行else部分
  49. return options.inverse(this);
  50. }
  51. });
  52. //将json对象用刚刚注册的Handlebars模版封装,得到最终的html,插入到基础table中。
  53. $('#tableList').html(myTemplate(data));

本例中,年龄大于20的童鞋个人主页被编码,直接展示出来;而年龄小于20的童鞋,个人主页被当成html解析,显示的是一个超链接。

handlebars不会编码 Handlebars.SafeString。如果你自定义一个helper,返回一段HTML代码,你需要返回 new Handlebars.SafeString(result)。此时,你需要手动对内容进行编码:

   
  1. Handlebars.registerHelper('link', function(text, url) {
  2. text = Handlebars.Utils.escapeExpression(text);
  3. url = Handlebars.Utils.escapeExpression(url);
  4. var result = '<a href="' + url + '">' + text + '</a>';
  5. return new Handlebars.SafeString(result);
  6. });

文章参考:

handlebars-js-tutorial-learn-everything-about-handlebars-js-javascript-templating

Handlebars.js 模板引擎

Handlebars.js 中文文档

淡忘~浅思猜你喜欢

js:简单的拖动效果

【译】Impress.js制作酷炫Presentation PPT

一个js闭包问题的解答

问题:关于一个贴友的js留言板的实现

DOM笔记(八):JavaScript执行环境和垃圾收集
无觅

转载请注明: 淡忘~浅思 » Handlebars.js初探

相关 [handlebars js] 推荐:

WebView JS 交互

- - ITeye博客
WebView加jquery做页面会怎么样呢. // 创建WebView对象. // 把programList添加到js的全局对象window中,. // 这样就可以使用window.programList来获取数据. * 定义js回调java函数. // 绑定键盘的向上,向下按钮事件触发相应的js事件.

JS游戏引擎

- 米随随 - HTML5研究小组
If you don’t have anything better to do and want to help fellow redditors interested in JS game dev out, feel free to fork the list and modify it as you like.

來源請求.js

- 红烧鲤鱼 - Blog: timdream
很早以前就想講了,但講了大概又會被戰. 相較於英文維基百科,中文維基百科在社會和歷史條目充滿了 systemic bias. 但是那些主觀論述又不是編輯者有意加進去的,而是某種編輯者存在的社會所給予的暗示(Inception?)與集體共識,而不是原本百科全書應該有的可驗證的事實. 因為是暗示又是共識,所以有自覺的百科編輯者反而是少數;中文維基只好長成現在這個樣子了.

Js删除节点

- - JavaScript - Web前端 - ITeye博客
 方式一:传this参数调用方法:.  方式二:js方法中通过选择器获取节点:. //此处删除的是a节点 }. 方式三:通过jQuery方式获取节点:(尚未测试,有待测试. 此处a标签传this到js中,js通过this(即a节点)取parent(即p节点). (1)p.remove();可直接删除整个p节点.

JS游戏引擎列表

- sku - 酷壳 - CoolShell.cn
这里有一个网址收集了关于JS游戏引擎开发库的一个列表,转过来. 关于使用JS和HTML5做的一些小游戏,可参见《HTML5 小游戏展示》. Name Latest Release License Type Notes The Render Engine 1.5.3 MIT 跨浏览器; 大规模 API; 开源. 2 gameQuery 0.5.1 CC BY-SA 2.5 和 jQuery 一起使用 gTile 0.0.1 Tile based.

Deck JS: HTML5 幻灯片

- L - LinuxTOY
Deck.js 是一组开源的 JavaScript 类库,方便使用现代的 HTML5/CSS3/JS 技术创建幻灯片. 该软件十分适用于开源项目介绍,交互式的方式比单纯的文字说明更简洁易懂. 不废话了,赶紧前往该项目主页去体验 HTML5 时代的幻灯片吧. 分类: Productivity |. 收藏到 del.icio.us |.

JS三维模型库 Three.js

- Le - 开源中国社区最新软件
Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它创建各种三维场景,包括了摄影机、光影、材质等各种对象. 你可以在它的主页上看到许多精采的演示. 不过,这款引擎目前还处在比较不成熟的开发阶段,其不够丰富的 API 以及匮乏的文档增加了初学者的学习难度(尤其是文档的匮乏) 演示:http://mrdoob.github.com/three.js/.

js Grid - 列表插件

- Bloger - 博客园-首页原创精华区
     js Grid - 列表插件.     1)Sponsor Flip Wall With jQuery & CSS一个非常不错的显示数据到网格里的插件. 点击后,缩略图会翻转,然后显示更多信息.      2)TableTree4J 是一个开源的基于javascript的树状菜单和表格控件,实用TableTree4J可以轻易实现带树状折叠效果的表格和树状折叠菜单.

Three js入门教程

- - 译言-电脑/网络/数码科技
译文来源: http://www.21haolou.com/articles/show/140. 我在自己的一些实验性项目中运用了 Three.js,它在处理浏览器3D效果方面表现优异. 通过Three js,你可以创建镜头(Cameras),物体(objects),光线(lights),材质(materials)等等,你还可以选择渲染器:可以使用HTML5的Canvas来绘制场景,也可选择使用WebGL或是SVG来渲染.

js对象深拷贝

- - ITeye博客
在做一个前台页面你的时候用到了一个自己写的List对象,在进行深拷贝的时候参考了网上的代码:. //对象扩展,tObj被扩展对象,sObj扩展对象. Object.extend(a,b);//a获得了b的所有属性. 我自己定义的list中没有定义constructor,所以执行sObj.constructor == Array会报错,我就修改为:.