handlebars自定义helper的写法
handlebars相对来讲算一个轻量级、高性能的模板引擎,因其简单、直观、不污染HTML的特性,我个人特别喜欢。另一方面,handlebars作为一个logicless的模板,不支持特别复杂的表达式、语句,只内置了一些基本的语法,像if、each这些。可惜的是就连if都十分弱,只能判断值是否为true/false,或转化后是否为true/false,不能对值进行比较。不过,handlebars提供了自定义helper的能力,通过自定义helper,可以实现非常丰富的功能。本篇来总结一下handlebars注册helper都有哪些方式,以及一些相关的知识。
helper大概可以分为两类,一类是用于格式化输出数据,使用起来像这样:{{formatDate date}},官方没有给起名字,我姑且叫做简单helper好了。另一类叫块级helper,块级helper有自己的作用域,可以拿到上下文数据,并可以定义渲染的内容,可以发挥的作用就比较大了。通过这两类helper,handlebars由一个弱逻辑的模板可以扩展出很强大的功能。通过registerHelper方法,我们便可以注册一个helper。下面先看一下简单helper。
简单helper
简单helper主要用来对数据进行格式化,例如我们经常会格式化日期、数字、金额等等。看一个例子就明白了,此处我写一个把数字进行千分位分割的helper,所谓千分位分割就是把123456789这样的值格式化为123,456,789.代码如下:
Handlebars.registerHelper('formatnumber', function(num, options){
num = num + '';
return num.replace(/(?=(?!^)(?:\d{3})+(?:\.|$))(\d{3}(\.\d+$)?)/g,',$1');
});
然后就可以在模板中使用:
{{formatnumber num}}
registerHelper的第一个参数是helper的名称,我这里把它叫做formatnumber,第二个参数是一个函数,该函数传入的第一个参数就是我们在使用helper时候的值,如上面的num,最后,函数return的内容就是我们模板中输出的内容。此外还会传入第二个参数options,options是一个对象,包含上下文相关的一些信息,不过在简单helper中用不到,我们会下面在块级helper中详细说说。
一个简单helper的定义就是如此简单,真如其名~
块级helper
块级helper的能力就强大很多,可以实现一些自己想要的迭代器,或者增强判断语句等。主要依赖的就是这个options参数。下面通过一个例子来说明一下。
handlebars的if语句只能进行true/false判断,如果我们想判断一个数字是否是偶数,我这么写是不可以的:{{#if num%2 == 0}},if不支持表达式,也不支持==这样的操作符。所以要想在模板中判断偶数,我们需要定义一个helper。代码如下:
//判断是否是偶数
Handlebars.registerHelper('if_even', function(value, options) {
console.log('value:', value); // value: 2
console.log('this:', this); // this: Object {num: 2}
console.log('fn(this):', options.fn(this)); // fn(this): 2是偶数
if((value % 2) == 0) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
然后我们造一个数据,写在模板中来看看:
var data3 = {
num : 2
}
模板中:
{{#if_even num}}
{{this.num}}是偶数
{{else}}
{{this.num}}是奇数
{{/if_even}}
得到的结果是输出“2是偶数”。通过在代码中log出的数据,可以看到用this可以取到当前的上下文主体,此处就是我们的定义好的数据对象了。另外一个比较重要的就是options.fn方法,此方法可以将你传入的上下文主体编译到模板,返回编译后的结果,在helper中,我们把this传了进去,于是在模板中也可以引用到它。最终options.fn返回编译后的结果:2是偶数。其实你也可以为options.fn传入其他的上下文对象,比如你要写一个迭代器,可以把数组的元素依次传入。
此处我们还看到了另一个方法,options.inverse,它是取相反的意思,对应了我们模板中的{{else}}标签,它会编译{{else}}中的的内容并返回结果,如果我们的helper中需要带else逻辑,用它就可以了。
块级helper在用的时候开头要加"#",并且要有结束符,就是上面的{{/if_even}}
接收多个参数的helper
自定义helper可以传入多个参数,只要依次写在registerHelper的函数中就可以了,看下面一个例子。
由于handlebars内置的if语句太弱,有时候我们需要判断像==、!=、>、<这样的逻辑,就必须自己写定义helper了。这样的helper需要传入左右操作数还有操作符,参数不只一个。下面这个compare是从别的地方抄来的,也是我在项目中用的最多的:
Handlebars.registerHelper('compare', function(left, operator, right, options) {
if (arguments.length < 3) {
throw new Error('Handlerbars Helper "compare" needs 2 parameters');
}
var operators = {
'==': function(l, r) {return l == r; },
'===': function(l, r) {return l === r; },
'!=': function(l, r) {return l != r; },
'!==': function(l, r) {return l !== r; },
'<': function(l, r) {return l < r; },
'>': function(l, r) {return l > r; },
'<=': function(l, r) {return l <= r; },
'>=': function(l, r) {return l >= r; },
'typeof': function(l, r) {return typeof l == r; }
}; if (!operators[operator]) {
throw new Error('Handlerbars Helper "compare" doesn\'t know the operator ' + operator);
} var result = operators[operator](left, right); if (result) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
使用的时候是这样:
{{#compare people.name '==' 'peter'}}
他的名字是peter
{{else}}
他的名字不是peter
{{/compare}}
可以看到在模板中传入的参数依次对应helper定义中的left、operator、options。同时定义中也是用了options.inverse,用来处理else的逻辑。
为helper传入hash参数
在模板中使用helper的时候,我们还可以为helper传入一些变量参数,叫做hash参数,在helper中可以通过options.hash拿到这些参数进行处理。这样helper的灵活性和可复用性就大大增强了。我们还是举例来说明。
定义一个名为list的helper,它的作用是循环输出数据,并把数据包裹在ul>li标签中。同时为了给元素增加不同的class,我把class名称作为hash来传入。helper代码如下:
Handlebars.registerHelper('list', function(items, options) {
var out = '<ul>';
for(var i=0, l=items.length; i<l; i++) {
var item = options.fn(items[i]);
out = out + '<li class="'+options.hash.class+'">' + item + '</li>';
}
return out + '</ul>';
});
在模板中,我使用了两次list,并传入不同的hash值:
{{#list people class="green"}}{{firstName}}-----{{lastName}}{{/list}}
{{#list people class="red"}}{{firstName}}-----{{lastName}}{{/list}}
定义以下数据做测试:
var data = {
people: [
{firstName: "Yehuda", lastName: "Katz"},
{firstName: "Carl", lastName: "Lerche"},
{firstName: "Alan", lastName: "Johnson"}
]
}
最终页面上生成的节点如下所示:
这样我们就重用了同一个helper,完成了更加灵活的任务。看到这里,是不是觉得helper很强大了呢,利用上面这些特性,我们可以写出非常丰富的功能了,足以满足开发需求。
其他
另外还有两点的小知识,补充在此处:
1. helper的销毁
调用Handlebars.unregisterHelper('list')即可销毁一个helper
2. 一次注册多个helper
andlebars.registerHelper({
foo: function() {},
bar: function() {}
});
handlebars作为一个弱逻辑的静态模板引擎,本身简单好用,没有太多冗余的东西,同时还提供了强大的扩展性,这也是我喜欢它的原因。希望通过本篇文章能让你更多的了解handlebars的helper,开始喜欢上它。
handlebars自定义helper的写法的更多相关文章
- handlebars自定义helper方法
handlebars相对来讲算一个轻量级.高性能的模板引擎,因其简单.直观.不污染HTML的特性,我个人特别喜欢.另一方面,handlebars作为一个logicless的模板,不支持特别复杂的表达式 ...
- handlebars.js 自定义helper(过滤)
将对象数据渲染到页面上: id 插入公共样式: handlebars.js 自定义helper(过滤)demo <script id="tbody-content-template&q ...
- Express 4 handlebars 不使用layout写法
Express 4 handlebars 不使用layout写法 Express node nodejs handlebars layout 最近刚开始学习使用nodejs. 使用express搭建了 ...
- sort方法和自定义比较器的写法
摘要 在做一些算法题时常常会需要对数组.自定义对象.集合进行排序. 在java中对数组排序提供了Arrays.sort()方法,对集合排序提供Collections.sort()方法.对自定义对象排序 ...
- asp.net MVC 自定义@helper 和自定义函数@functions小结
asp.net Razor 视图具有.cshtml后缀,可以轻松的实现c#代码和html标签的切换,大大提升了我们的开发效率.但是Razor语法还是有一些棉花糖值得我们了解一下,可以更加强劲的提升我们 ...
- Android 自定义AlertDialog的写法和弹出软键盘和覆盖状态栏
private void showMyDialog(int layoutId){ AlertDialog myDialog = new AlertDialog.Builder(context).cre ...
- 关于vue 自定义组件的写法与用法
最近在网上看到很多大神都有写博客的习惯,坚持写博客不但可以为自己的平时的学习做好记录积累 无意之中也学还能帮助到一些其他的朋友所以今天我也注册一个账号记录一下学习的点滴!当然本人能力实在有限写出的文章 ...
- priority_queue 中存放pair时,自定义排序的写法
struct cmp {template <typename T, typename U> bool operator()(T const &left, U const & ...
- css 自定义悬浮窗写法
HTML: css(sass): 复制代码 .info { } &:hover::after { content: attr(data-title); display: inline-bloc ...
随机推荐
- C# 中参数验证方式的演变
一般在写方法的时候,第一步就是进行参数验证,这也体现了编码者的细心和缜密,但是在很多时候这个过程很枯燥和乏味,比如在拿到一个API设计文档的时候,通常会规定类型参数是否允许为空,如果是字符可能有长度限 ...
- async & await 的前世今生(Updated)
async 和 await 出现在C# 5.0之后,给并行编程带来了不少的方便,特别是当在MVC中的Action也变成async之后,有点开始什么都是async的味道了.但是这也给我们编程埋下了一些隐 ...
- [C#] 简单的 Helper 封装 -- RandomHelper
using System; namespace Wen.Helpers { /// <summary> /// 随机数助手 /// </summary> public seal ...
- Kooboo CMS技术文档之一:Kooboo CMS技术背景
语言平台 依赖注入方案 存储模型 1. 语言平台 Kooboo CMS基于.NET Framework 4.x,.NET Framework 4.x的一些技术特性成为站点开发人员使用Kooboo CM ...
- 从display:run-in;中学习新技能
有时我们想在一行内显示一个标题,以及一段内容,虽然看起来比较简单,但是为了语义化用dl比较合适,但是它默认是block元素,改成inline?那么有多段呢?不就都跑上来了?用float?那问题也挺多. ...
- [修正] Firemonkey TFrame 存档后,下次载入某些事件连结会消失(但源码还在)
问题:Firemonkey TFrame 存档后,下次载入某些事件连结会消失(但源码还在) 解决:(暂时方法) type TTestFrame = class(TFrame) public const ...
- python之最强王者(9)——函数
1.Python 函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但 ...
- nginx服务器安装及配置文件详解
nginx在工作中已经有好几个环境在使用了,每次都是重新去网上扒博客,各种编译配置,今天自己也整理一份安装文档和nginx.conf配置选项的说明,留作以后参考.像负载均衡配置(包括健康检查).缓存( ...
- MongoDB学习笔记二—Shell操作
数据类型 MongoDB在保留JSON基本键/值对特性的基础上,添加了其他一些数据类型. null null用于表示空值或者不存在的字段:{“x”:null} 布尔型 布尔类型有两个值true和fal ...
- linux下 lvm 磁盘扩容
打算给系统装一个oracle,发现磁盘空间不足.在安装系统的时候我选择的是自动分区,系统就会自动以LVM的方式分区.为了保证系统后期的可用性,建议所有新系统安装都采用LVM,之后生产上的设备我也打算这 ...