资讯专栏INFORMATION COLUMN

Handlebars—semantic template engine

cyrils / 3006人阅读

摘要:维护起来将是我们开发的噩梦。的都是这种的闭合结构的判断只能判断和,没办法进行这种的逻辑判断。它的设定就是如此,它认为逻辑判断的内容不应该出现在模板中。因为的输出默认转义,几乎所有的模板引擎输出默认都是转义的,避免攻击。

概述

刚接触前端的时候,师傅就给我推荐了Handlebars,自己也蛮喜欢它的语法。到现在,Handlebars都已经更新到3.0.3了,是时候重新过一遍文档了。

引入

要使用Handlebars,首先你得download,然后再页面引入,就像这样

</>复制代码

如果你使用了模块化的管理工具,如requirejs、webpack、seajs,不用担心。Handlebars是支持amd、cmd规范的,使用就像这样

</>复制代码

  1. var Handlebars=require("Handlebars");
基本

来一个简单的例子,向服务器发起了一个ajax请求获取了一个对象数组,要渲染到页面上。数据格式是这样的

</>复制代码

  1. var data = [
  2. {
  3. name: "xxx",
  4. age: 10
  5. },
  6. {
  7. name: "zzz",
  8. age: 12
  9. },
  10. {
  11. name: "yyy",
  12. age: 9
  13. }
  14. ];

首先我们要建立一个模板结构,也就是我们的Html,为了展示和逻辑分离,我们不应该将模版内容放到js当中,先看下不好的做法:

</>复制代码

  1. var $container = $("#container");//容器
  2. var content = "";
  3. data.forEach(function (item) {
  4. content += "

    " + item.name + ":" + item.age + "

    ";
  5. });
  6. $container.html(content);

当Html内容一多,各种单引号,双引号,可读性、结构性太差。维护起来将是我们开发的噩梦。
使用Handlebars,首先我们将Html抽出来,就像用script标签包裹起来,放入我们当前的页面中,就像这样

</>复制代码

记得改变type类型,这样浏览器就不会把标签里的内容当作js执行。然后编写我们的代码

</>复制代码

  1. var $container = $("#container");//容器
  2. var source = $("#template-user").html();//获取到html结构
  3. var template = Handlebars.compile(source);//编译成模板
  4. var html = template(data);//生成完成的html结构
  5. $container.html(html);//插入dom

Handlebars的基本使用就如上了,用{{ }}输出内容。记住了

</>复制代码

  1. 模板最外层的this就是你调用template方法时传入的对象

Block

我们使用模板一般都是为了遍历对象结构,然后渲染到页面上。有人说了如果我就传递个字符串进去呢?直接

</>复制代码

  1. $container.html(str);

用JBM模板!使用模板最常用的就是if判断和each遍历了,下面来详细讲解。

</>复制代码

  1. Handlebars的block都是这种{{#each}}{{/each}}的闭合结构

if/unless if

Handlebars的if判断只能判断true和false,没办法进行这种a===3的逻辑判断。它的设定就是如此,它认为逻辑判断的内容不应该出现在模板中。看个例子

</>复制代码

  1. #template
  2. {{#if isEdit}}
  3. isEdit

  4. {{/if}}
  5. {{#if email}}
  6. {{email}}

  7. {{/if}}
  8. {{#if num}}
  9. {{num}}

  10. {{/if}}
  11. #数据
  12. var data = {
  13. isEdit: true,
  14. email: "",
  15. num: "0"
  16. };
  17. #页面效果
  18. isEdit
  19. 0

Handlebars if在判断前会做类型转换,如""、undefined、null、0、[]等都会被识别为false。而实际情况下我们都用数字来标识不同的状态,碰到这种数据我们需要预处理下,才能渲染哦。

if else

</>复制代码

  1. #template
  2. {{#if isEdit}}
  3. isEdit

  4. {{else}}
  5. isNotEdit

  6. {{/if}}
  7. #数据
  8. var data = {
  9. isEdit: false
  10. };
  11. #页面效果
  12. isNotEdit

看看多分支是咋子写的

</>复制代码

  1. #template
  2. {{#if isEdit}}
  3. isEdit

  4. {{else if isRead}}
  5. isNotEdit isRead

  6. {{else}}
  7. isNotRead

  8. {{/if}}
  9. #数据
  10. var data = {
  11. isEdit: false,
  12. isRead: false
  13. };
  14. #页面效果
  15. isNotRead
unless

作用刚好跟if相反,if是true的时候返回,unless是false的时候返回,看例子

</>复制代码

  1. #template
  2. {{#unless isEdit}}
  3. isNotEdit

  4. {{else unless isRead}}
  5. isRead

  6. {{else}}
  7. isNotRead

  8. {{/unless}}
  9. #数据
  10. var data = {
  11. isEdit: true,
  12. isRead:true
  13. };
  14. #页面效果
  15. isNotRead
each 遍历数组

</>复制代码

  1. #template
  2. {{#each this}}
  3. {{this.name}}:{{this.age}}

  4. {{else}}
  5. no data

  6. {{/each}}
  7. #数据
  8. var data = [
  9. {
  10. name: "yyy",
  11. age: 23
  12. },
  13. {
  14. name: "zzz",
  15. age: 55
  16. }
  17. ];
  18. #页面效果
  19. yyy:23
  20. zzz:55

each也支持else的判断。each里面的this是指向单个对象的,这个时候this可以省略不写,效果是一样的

</>复制代码

  1. {{#each this}}
  2. {{name}}:{{age}}

  3. {{/each}}

遍历数组的时候一般都会输出序号,怎么破?

</>复制代码

  1. #template
  2. {{#each this}}
  3. {{this.name}}:{{this.age}}

  4. {{/each}}
  5. #页面效果
  6. 0 yyy:23
  7. 1 zzz:55

通过@index或者@key都可以获得序号,但是序号都是从0开始的,这个比较坑!如果要从1开始,得自己写个helper处理,真实日了狗了!

遍历数组的需要判别是第一个还是最后一个怎么破?

</>复制代码

  1. #template
  2. {{#each this}}
  3. {{name}}:{{age}} {{#if @first}}first{{/if}} {{#if @last}}last{{/if}}

  4. {{/each}}
  5. #页面效果
  6. yyy:23 first
  7. zzz:55 last

通过@first和@last可以判断是否是数组的第一个或者最后一个。

</>复制代码

  1. 如果在加上@odd、@even就完美了!

遍历对象

真实的应用场景下,服务器很可能会返回一个map,就是js当中的对象,这个时候我们是不知道有哪些key的,如何遍历这个map呢?

</>复制代码

  1. #template
  2. {{#each this}}
  3. {{@key}}:{{this}}

  4. {{/each}}
  5. #数据
  6. var data = {
  7. name: "yyy",
  8. age: 23
  9. };
  10. #页面效果
  11. name:yyy
  12. age:23

通过@key可以获取到对象的key名称。

Html转义

假想这样一个场景,通过ajax获取到了一段富文本内容,然后展示在页面中

</>复制代码

  1. #template
  2. {{richText}}
  3. #数据
  4. var data = {
  5. richText: "
    this is rich text
    "
  6. };
  7. #页面效果
  8. this is rich text

这个时候你肯定会想了,真实日了狗了,怎么原样输出了,没有解析成html啊。因为{{richText}}的输出默认转义Html,几乎所有的模板引擎输出默认都是转义Html的,避免xss攻击。如果你想避免转义,请这样用

</>复制代码

  1. {{{richText}}}
Helpers

列表输出的时候,如果有时间字段,一般都需要格式化时间,拿到数据后我们还得处理

</>复制代码

  1. #template
  2. {{#each this}}
  3. {{name}}:{{addTime}}

  4. {{/each}}
  5. #js
  6. var data = [
  7. {
  8. name: "xxx",
  9. addTime: new Date()
  10. },
  11. {
  12. name: "zzz",
  13. addTime: new Date()
  14. }
  15. ];
  16. data.forEach(function(item){
  17. item.addTime=moment(item.addTime).format("YYYY-MM-DD");
  18. });
  19. #页面效果
  20. xxx:2015-05-26
  21. zzz:2015-05-26

换个页面碰到类似的情景,相同的代码又得写一面,冗余的代码太多了,不利于后期维护。怎么破?

</>复制代码

  1. #template
  2. {{#each this}}
  3. {{name}}:{{moment addTime}}

  4. {{/each}}
  5. #js
  6. Handlebars.registerHelper("moment", function (date, options) {
  7. var formatStr = options.hash.format || "YYYY-MM-DD";
  8. return new Handlebars.SafeString(moment(date).format(formatStr));
  9. });
  10. var data = [
  11. {
  12. name: "xxx",
  13. addTime: new Date()
  14. },
  15. {
  16. name: "zzz",
  17. addTime: new Date()
  18. }
  19. ];

注册一个全局的moment,这样所有的时间格式化,都可以通过{{moment time}}调用,维护的成本大大降低。
需要注意的是helper如{{moment arg1 arg2}}的形式最多添加两个参数可以被注册函数获取到,如果要添加多个参数,请使用hash的形式

</>复制代码

  1. #template
  2. {{query name "arg2" hash1="hash1" hash2="hash2"}}

  3. #数据
  4. Handlebars.registerHelper("query", function (arg1, arg2, options) {
  5. console.log("arg1:" + arg1);
  6. console.log("arg2:" + arg2);
  7. console.log(options.hash);
  8. });
  9. var data = {
  10. name: "jacky"
  11. };
  12. #控制台
  13. $ arg1:jacky
  14. $ arg2:arg2
  15. $ Object {hash2: "hash2", hash1: "hash1"}

Handlebars.SafeString就是不转义Html,如果想转义Html直接return内容即可。

</>复制代码

  1. #template
  2. {{safe}}

  3. #js
  4. Handlebars.registerHelper("safe", function () {
  5. return new Handlebars.SafeString("
    safe string
    ")
  6. });
  7. #页面效果
  8. safe string
Partials

共享同一个模板内容,后端渲染使用的比较多

</>复制代码

  1. #template
  2. {{> footer}}

  3. #js
  4. Handlebars.registerPartial("footer", function () {
  5. return new Handlebars.SafeString("
    This is footer
    ")
  6. });
  7. var data = {
  8. name: "jacky"
  9. };
  10. #页面效果
  11. This is footer
../

这样一个数据结构渲染到页面上

</>复制代码

  1. #template
  2. {{#each company.prodList}}
  3. {{prodName}} {{company.comName}}

  4. {{/each}}
  5. #js
  6. var data = {
  7. company: {
  8. comName: "技术有限公司",
  9. prodList: [
  10. {
  11. prodName: "产品1"
  12. },
  13. {
  14. prodName: "产品2"
  15. }
  16. ]
  17. }
  18. };
  19. #页面效果
  20. 产品1
  21. 产品2

等等好像有点不对劲啊,为啥没有公司名称呢?前面说到each里面的this都是指向单个对象的,{{prodName}} {{company.comName}}这种写法省略了this,还原下

</>复制代码

  1. {{#each company.prodList}}
  2. {{this.prodName}} {{this.company.comName}}

  3. {{/each}}

知道问题在哪里了吧。怎么破?

</>复制代码

  1. {{#each company.prodList}}
  2. {{prodName}} {{../company.comName}}

  3. {{/each}}

通过../回到each之外。下面来填另一个经典的坑

</>复制代码

  1. #template
    • {{#each this}}
      • {{#each this}}
      • {{@../index}}-{{@index}} {{this}}
      • {{/each}}
    • {{/each}}
  2. #js
  3. var data = [
  4. ["aaa", "bbb", "ccc"],
  5. ["ffffd", "eee", "fff"]
  6. ];
  7. #页面效果
  8. 0-0 aaa
  9. 0-1 bbb
  10. 0-2 ccc
  11. 1-0 ffffd
  12. 1-1 eee
  13. 1-2 fff
代码链接

Github

参考

Handlebars

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64359.html

相关文章

  • 用100行代码,完成自己的前端构建工具!

    摘要:行代码,你将拥有一个现代化规范测试驱动高延展性的前端构建工具。在阅读前,给大家一个小悬念什么是链式操作中间件机制如何读取构建文件树如何实现批量模板渲染代码转译如何实现中间件间数据共享。函数将参数中的挂载到上,并返回以便于链式操作即可。 ES2017+,你不再需要纠结于复杂的构建工具技术选型。 也不再需要gulp,grunt,yeoman,metalsmith,fis3。 以上的这些构建...

    haitiancoder 评论0 收藏0
  • 使用webpack 构建handlebars+jquery+bootstrap的开发环境

    摘要:配置文件的编写在目录下。当然可以根据其他的解析搭建不同开发环境,都是很容易的。 前言 自从webpack 诞生,就开启了webpack的时代,从其他的老大哥打包工具过度而来,详情可看: https://github.com/tstrilogy/... 0. 资源 list of loader: https://webpack.github.io/doc... (关于webpack 所...

    pf_miles 评论0 收藏0
  • 走进Vue-cli源码,自己动手搭建前端脚手架工具

    摘要:前言前段时间看了一些的源码,收获颇深。介绍是一款非常优秀的用于迅速构建基于的应用工具。不影响阅读源码,直接忽略掉。引入的包发送请求的工具。自定义工具用于询问开发者。 前言 前段时间看了一些vue-cli的源码,收获颇深。本想找个时间更新一篇文章,但是最近事情比较多,没有时间去整理这些东西。趁这两天闲了下来,便整理了一下,然后跟大家分享一下。如果小伙伴们读完之后,跟我一样收获很多的话,还...

    Apollo 评论0 收藏0
  • handlebars.js模板引擎

    摘要:基于,可以在中导入模板。利用对象函数替换对象或者运行函数支持点语法可以对象等属性值使用时,直接标签引入文件。模块会自动匹配相应的数值,对象或者是函数。也可以单独建立一个模板,或者可以用来唯一确定一个模板,是固定写法,不可或缺。 前言:常用的末班引擎有很多,但写法都大同小异。handlebars.js就是一个纯JS库,因此你可以向其他脚本一样用script包起来。调用内部封装好的功能。 ...

    SimpleTriangle 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<