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,开始喜欢上它。

时间: 2024-12-15 20:17:59

handlebars自定义helper的写法的相关文章

Handlebars自定义Helper的使用方法

环境是backbone! 首先要声明: 1 Handlebars.registerHelper('roomnameDisplay', function(flag) { 2 return flag?'roomname-hide':''; 3 }); 在模板里的调用: var SecretList = fliza.List.extend({ …………其他代码 ' <a class="fromroom {{roomnameDisplay roomnameHide}}" target=&

Express 4 handlebars 不使用layout写法

Express 4 handlebars 不使用layout写法 Express node nodejs handlebars layout 最近刚开始学习使用nodejs. 使用express搭建了一个基于handlebars的模板引擎的基础项目. 发现所有页面都继承了layout... 那layout怎么才能不继承layout呢? 直接上代码: router.get('/', function(req, res) { res.render('home', {layout: false});

自定义 Helper Method

摘自小牛之路 自定义 Helper Method 模板 前面我们简要介绍了 Helper Method 模板根据 Model 元数据生成 Html 元素的便捷之处.但有时候MVC提供的模板并不能满足我们的需求,这时我们可以为 Model 对象的某个属性自定义一个 Helper Method 模板. 在前文中我们知道,使用 Html.DropDownList(For) 可以为我们创建一个下拉列表,但这个方法有一点不好使,每次使用都需要给它构造器的第二个参数指定数据源,很是不方便.对于频繁使用的下拉

sort方法和自定义比较器的写法

摘要 在做一些算法题时常常会需要对数组.自定义对象.集合进行排序. 在java中对数组排序提供了Arrays.sort()方法,对集合排序提供Collections.sort()方法.对自定义对象排序时要自己重写比较器,对象数组则调用Arrays.sort(),对象集合则调用Collections.sort().两个方法默认都是升序,也可以重写比较器,实现降序. 对数组排序 sort函数模板, 以int型数组为例: Arrays.sort(int[] a, Comparator<Integer>

AspNet MVC4 教学-27:Asp.Net MVC4 自定义helper及function的快速Demo

A.创建Basic类型项目. B.创建App_Code文件夹,在里面创建2个cshtml文件: MyHelper.cshtml: @helper MyTruncate(string input, int length) { <text>来自App_Code中的Helper->MyTruncate:</text> if (input.Length <= length) { @input } else { @input.Substring(0, length) } } @h

Laravel Vuejs 实战:开发知乎 (33)自定义helper方法

参考: laravel 中添加自定义辅助函数helpers.php laravel自定义公共函数的引入怎么使用 Laravel增加自定义助手函数 Laravel 添加自定义全局函数 laravel 添加帮助类在helper 辅助函数 Laravel 目录结构:自定义函数的存放位置 创建 app/Http/helpers.php文件 修改 compose.json文件 1 "autoload": { 2 "classmap": [ 3 "database/s

自定义标签的写法

例如我们在一个html文档中写一个自定义的标签 <%@taglib uri="" prefix="c1"%>    //uri是一个命名空间,perfix是一个前缀 在html的正文中我们写上 <c1: msg="" qty="">     //c1就是这个标签的标签名,msg和qty是属性 我们要定义这个标签就要先些上这个标签的类,这个类要继承SimpleTagSupport public class

vue之自定义组件的写法与用法

三个技能,父组件 -> 子组件传值(props).子组件 -> 父组件传值($emit).以及插槽(slot):对于一个独立的组件来说,props是用来为组件内部注入核心的内容:$emit用来使这个独立的组件通过一些逻辑来融入其他组件中.举个具体点的例子,假如你要做一辆车,车轮是要封装的一个独立组件,props指的就是根据整个车的外形你可以给轮子设置一些你想要的且符合车风格的花纹,图案等:而$emit的作用则是让这些轮子能够和整辆车完美契合的运作起来. (1)使用props可以实现父子组件之间

IOS中AppDelegate类中的方法触发时机-----自定义AppDelegate的写法

@implementation AppDelegate //当应用程序加载时触发,创建window窗口对象,让对象的window成为程序的主窗口,并且可视. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen ma