Handlebars.js入门教程
转自https://segmentfault.com/a/1190000002796397
概述
刚接触前端的时候,师傅就给我推荐了Handlebars,自己也蛮喜欢它的语法。到现在,Handlebars都已经更新到3.0.3了,是时候重新过一遍文档了。
引入
要使用Handlebars,首先你得download,然后再页面引入,就像这样
<script src="script/lib/jquery.js"></script>
<script src="script/lib/handlebars.js"></script>
如果你使用了模块化的管理工具,如requirejs、webpack、seajs,不用担心。Handlebars是支持amd、cmd规范的,使用就像这样
var Handlebars=require('Handlebars');
基本
来一个简单的例子,向服务器发起了一个ajax请求获取了一个对象数组,要渲染到页面上。数据格式是这样的
var data = [{name: 'xxx',age: 10},{name: 'zzz',age: 12},{name: 'yyy',age: 9}
];
首先我们要建立一个模板结构,也就是我们的Html,为了展示和逻辑分离,我们不应该将模版内容放到js当中,先看下不好的做法:
var $container = $('#container');//容器
var content = '';data.forEach(function (item) {content += '<p>' + item.name + ':' + item.age + '</p>';
});$container.html(content);
当Html内容一多,各种单引号,双引号,可读性、结构性太差。维护起来将是我们开发的噩梦。
使用Handlebars,首先我们将Html抽出来,就像用script标签包裹起来,放入我们当前的页面中,就像这样
<body><div id="container"></div><script type="text/x-handlebars-template" id="template-user">{{#each this}}<p>{{name}}:{{age}}</p>{{/each}}</script><script src="script/lib/jquery.js"></script><script src="script/lib/handlebars.js"></script><script src="script/my/basicuse.js"></script>
</body>
记得改变type类型,这样浏览器就不会把标签里的内容当作js执行。然后编写我们的代码
var $container = $('#container');//容器
var source = $('#template-user').html();//获取到html结构
var template = Handlebars.compile(source);//编译成模板
var html = template(data);//生成完成的html结构
$container.html(html);//插入dom
Handlebars的基本使用就如上了,用{{ }}输出内容。记住了
模板最外层的this就是你调用template方法时传入的对象
Block
我们使用模板一般都是为了遍历对象结构,然后渲染到页面上。有人说了如果我就传递个字符串进去呢?直接
$container.html(str);
用JBM模板!使用模板最常用的就是if判断和each遍历了,下面来详细讲解。
Handlebars的block都是这种{{#each}}{{/each}}的闭合结构
if/unless
if
Handlebars的if判断只能判断true和false,没办法进行这种a===3的逻辑判断。它的设定就是如此,它认为逻辑判断的内容不应该出现在模板中。看个例子
#template
{{#if isEdit}}<p>isEdit</p>
{{/if}}
{{#if email}}<p>{{email}}</p>
{{/if}}
{{#if num}}<p>{{num}}</p>
{{/if}} #数据
var data = {isEdit: true,email: '',num: '0'
};#页面效果
isEdit
0
Handlebars if在判断前会做类型转换,如''、undefined、null、0、[]等都会被识别为false。而实际情况下我们都用数字来标识不同的状态,碰到这种数据我们需要预处理下,才能渲染哦。
if else
#template
{{#if isEdit}}<p>isEdit</p>
{{else}}<p>isNotEdit</p>
{{/if}} #数据
var data = {isEdit: false
};#页面效果
isNotEdit
看看多分支是咋子写的
#template
{{#if isEdit}}<p>isEdit</p>
{{else if isRead}}<p>isNotEdit isRead</p>
{{else}}<p>isNotRead</p>
{{/if}} #数据
var data = {isEdit: false,isRead: false
};#页面效果
isNotRead
unless
作用刚好跟if相反,if是true的时候返回,unless是false的时候返回,看例子
#template
{{#unless isEdit}}<p>isNotEdit</p>
{{else unless isRead}}<p>isRead</p>
{{else}}<p>isNotRead</p>
{{/unless}} #数据
var data = {isEdit: true,isRead:true
};#页面效果
isNotRead
each
遍历数组
#template
{{#each this}}<p>{{this.name}}:{{this.age}}</p>
{{else}}<p>no data</p>
{{/each}}#数据
var data = [{name: 'yyy',age: 23},{name: 'zzz',age: 55}
];#页面效果
yyy:23
zzz:55
each也支持else的判断。each里面的this是指向单个对象的,这个时候this可以省略不写,效果是一样的
{{#each this}}<p>{{name}}:{{age}}</p>
{{/each}}
遍历数组的时候一般都会输出序号,怎么破?
#template
{{#each this}}<p>{{this.name}}:{{this.age}}</p>
{{/each}} #页面效果
0 yyy:23
1 zzz:55
通过@index或者@key都可以获得序号,但是序号都是从0开始的,这个比较坑!如果要从1开始,得自己写个helper处理,真实日了狗了!
遍历数组的需要判别是第一个还是最后一个怎么破?
#template
{{#each this}}<p>{{name}}:{{age}} {{#if @first}}first{{/if}} {{#if @last}}last{{/if}}</p>
{{/each}}#页面效果
yyy:23 first
zzz:55 last
通过@first和@last可以判断是否是数组的第一个或者最后一个。
如果在加上@odd、@even就完美了!
遍历对象
真实的应用场景下,服务器很可能会返回一个map,就是js当中的对象,这个时候我们是不知道有哪些key的,如何遍历这个map呢?
#template
{{#each this}}<p>{{@key}}:{{this}}</p>
{{/each}}#数据
var data = {name: 'yyy',age: 23
};#页面效果
name:yyy
age:23
通过@key可以获取到对象的key名称。
Html转义
假想这样一个场景,通过ajax获取到了一段富文本内容,然后展示在页面中
#template
<div>{{richText}}</div>#数据
var data = {richText: '<div>this is rich text</div>'
};#页面效果
<div>this is rich text</div>
这个时候你肯定会想了,真实日了狗了,怎么原样输出了,没有解析成html啊。因为{{richText}}的输出默认转义Html,几乎所有的模板引擎输出默认都是转义Html的,避免xss攻击。如果你想避免转义,请这样用
{{{richText}}}
Helpers
列表输出的时候,如果有时间字段,一般都需要格式化时间,拿到数据后我们还得处理
#template
{{#each this}}<p>{{name}}:{{addTime}}</p>
{{/each}}#js
var data = [{name: 'xxx',addTime: new Date()},{name: 'zzz',addTime: new Date()}
];data.forEach(function(item){item.addTime=moment(item.addTime).format('YYYY-MM-DD');
});#页面效果
xxx:2015-05-26
zzz:2015-05-26
换个页面碰到类似的情景,相同的代码又得写一面,冗余的代码太多了,不利于后期维护。怎么破?
#template
{{#each this}}<p>{{name}}:{{moment addTime}}</p>
{{/each}}#js
Handlebars.registerHelper('moment', function (date, options) {var formatStr = options.hash.format || 'YYYY-MM-DD';return new Handlebars.SafeString(moment(date).format(formatStr));
});var data = [{name: 'xxx',addTime: new Date()},{name: 'zzz',addTime: new Date()}
];
注册一个全局的moment,这样所有的时间格式化,都可以通过{{moment time}}调用,维护的成本大大降低。
需要注意的是helper如{{moment arg1 arg2}}的形式最多添加两个参数可以被注册函数获取到,如果要添加多个参数,请使用hash的形式
#template
<p>{{query name 'arg2' hash1='hash1' hash2='hash2'}}</p>#数据
Handlebars.registerHelper('query', function (arg1, arg2, options) {console.log('arg1:' + arg1);console.log('arg2:' + arg2);console.log(options.hash);
});var data = {name: 'jacky'
};#控制台
$ arg1:jacky
$ arg2:arg2
$ Object {hash2: "hash2", hash1: "hash1"}
Handlebars.SafeString就是不转义Html,如果想转义Html直接return内容即可。
#template
<p>{{safe}}</p>#js
Handlebars.registerHelper('safe', function () {return new Handlebars.SafeString('<div>safe string</div>')
});#页面效果
safe string
Partials
共享同一个模板内容,后端渲染使用的比较多
#template
<p>{{> footer}}</p>#js
Handlebars.registerPartial('footer', function () {return new Handlebars.SafeString('<div>This is footer</div>')
});var data = {name: 'jacky'
};#页面效果
This is footer
../
这样一个数据结构渲染到页面上
#template
{{#each company.prodList}}<p>{{prodName}} {{company.comName}}</p>
{{/each}}#js
var data = {company: {comName: '技术有限公司',prodList: [{prodName: '产品1'},{prodName: '产品2'}]}
};#页面效果
产品1
产品2
等等好像有点不对劲啊,为啥没有公司名称呢?前面说到each里面的this都是指向单个对象的,{{prodName}} {{company.comName}}这种写法省略了this,还原下
{{#each company.prodList}}<p>{{this.prodName}} {{this.company.comName}}</p>
{{/each}}
知道问题在哪里了吧。怎么破?
{{#each company.prodList}}<p>{{prodName}} {{../company.comName}}</p>
{{/each}}
通过../回到each之外。下面来填另一个经典的坑
#template
<ul>{{#each this}}<li><ul>{{#each this}}<li>{{@../index}}-{{@index}} {{this}}</li>{{/each}}</ul></li>{{/each}}
</ul>#js
var data = [['aaa', 'bbb', 'ccc'],['ddd', 'eee', 'fff']
];#页面效果
0-0 aaa
0-1 bbb
0-2 ccc
1-0 ddd
1-1 eee
1-2 fff
代码链接
Github
参考
Handlebars
Handlebars.js入门教程相关推荐
- Vue.js入门教程-组件注册
一.组件创建 1.1 创建步骤 创建Vue的组件都有三个基本步骤是 [①创建组件构造器.②注册组件和③使用组件]. 1.2 基本示例 比如,我们创建一个Button组件. // 1. 创建一个组件构造 ...
- js模版引擎handlebars.js实用教程——结束语
返回目录 有了这些功能,[ajax json Handlebars]替代[vo el表达式]不成问题,新时代的曙光已经来临,最佳解决方案在此,您还等什么? 教程到此结束...祝读者学习愉快... 转载 ...
- js读取http chunk流_极简 Node.js入门 教程双工流
点击上方蓝字关注我们 小编提示: 本文是由 ICBU 的谦行小哥哥出品,我们会持续发出极简 Node.js入门 教程,敬请期待哦,文中有比较多的演示代码建议横屏阅读 双工流就是同时实现了 Readab ...
- Node.js 入门教程 23 使用 npm 的语义版本控制 24 卸载 npm 软件包 25 npm 全局或本地的软件包
Node.js 入门教程 Node.js官方入门教程 Node.js中文网 本文仅用于学习记录,不存在任何商业用途,如侵删 文章目录 Node.js 入门教程 23 使用 npm 的语义版本控制 24 ...
- Vue.js入门教程(适合初学者)
Vue.js入门教程 Vue官网网址:Vue.js 中文网 Vue.js Vue.js是渐进式JavaScript 框架,是一套构建用户界面的渐进式框架.也可以说Vue.js 是一个用来构建网页界面的 ...
- Node.js 入门教程 6 V8 JavaScript 引擎
Node.js 入门教程 Node.js官方入门教程 Node.js中文网 本文仅用于学习记录,不存在任何商业用途,如侵删 文章目录 Node.js 入门教程 6 V8 JavaScript 引擎 6 ...
- Ember.js入门教程、博文汇总
第一章 对象模型 Ember.js 入门指南--类的定义.初始化.继承 Ember.js 入门指南--类的扩展(reopen) Ember.js 入门指南--计算属性(compute properti ...
- egg.js入门教程视频文件(转载于cnode社区)
记得上篇博客我满怀欣喜的去搞富文本,结果撞的头破血流. 简直是惨不忍睹.后来我也说了,我的那个有比较严重的问题,后期会考虑重构.(第一版已经放弃了) 之后我说我会去看关于后端nodejs koa框架方 ...
- Two.js入门教程
项目中需要前端画svg图像,直接在html上写标签不太优雅,于是找到了Two.js这个第三方类库,使用其完成了开发任务后,分享下使用心得,就算是入门教程了. 其官方网站为https://two.js. ...
最新文章
- jemeter多场景混合案例_Jmeter多业务混合场景如何设置各业务所占并发比例
- Mysql之一:mysqldump和LVM逻辑卷快照
- JZOJ 1637. 【ZJOI2009】狼和羊的故事
- win7安装git客户端和简单配置
- sql和sqlite常用查询语句
- 总结2:上传图片至指定服务器
- JBoss5开发web service常见问题
- VS2008 Qt Designer 中自定义信号槽
- 选择更安全的方式注册你的puppet节点
- 分享400多道算法题,来挑战吧
- mysql 索引使用不当_MySQL笔记:select默认使用不当索引导致的巨大性能损失问题_MySQL...
- 电脑更新重启后黑屏_电脑黑屏重启还是黑屏的解决方法教程
- C/C++语言函数之strlen函数用法
- java 1.5 jdk_jdk1.5安装及配置
- java如何实现对word设置只读或者加密
- 微信聊天记录如何恢复
- 星际争霸2-数据编辑器-菜鸟入门
- PM应该了解的九大项目管理问题
- 安卓之父安迪·鲁宾:让乔布斯羡慕嫉妒恨的人
- js提示“未结束的字符串常量”