Handlebars自定义Helper

Author : lovecicy

关于Handlebars模板的使用,官网给出的文档实在有点凌乱,好在上手容易,看看官方的文档就能入门了。但是对于helper的自定义,官网没有做详细的介绍,后来发现一篇比较好的英文教程,真正可以说从入门到精通,详细介绍了handlebars的使用,有兴趣的可以点这里,这里只翻译其中关于自定义Helper的章节。
———————————————–分割线——————————————————-
Handlebars.js自定义Helpers

除了前面讨论的内建的helper,Handlebars允许我们添加自定义的helper,相对于内建的helper,这更为重要,因为我们可以在自定义的helper中添加复杂的逻辑。如果你愿意,你甚至可以用我们自定义的helper重新定义内建的helper,但我觉得你不至于这么闲的蛋疼。

在自定义的helper中,我们可以添加任何的JS逻辑。我们需要在所有Handlebars JS代码之前注册helper。自定义的helper在JS代码中创建,而非Handlebars的模板中。

创建helper有两种方式:块级helper与非块级helper。

一、自定义函数helper

因为内建的helper中没有条件判断的逻辑,所以我就以条件逻辑判断为例,做一个简单的自定义函数helper。

数据对象为:

var contextObj = {score:85, userName:"Mike"};

首先,使用Handlebars.registerHelper方法注册自定义的helper。这个方法接收两个参数,第一个为字符串类型,用作helper的名字,第二个参数为一个函数,接收任意个数的参数。示例代码如下:

Handlebars.registerHelper ("theNameOfTheHelper", function (theScore) {
    console.log("Grade: " + theScore );
    var userGrade = "C";
    if (theScore >= 90) {
        return "A" ;
    }
    else if (theScore >= 80 && theScore < 90) {
        return "B" ;
    } else if (theScore >= 70 && theScore < 80) {
        return "C" ;
    }
    else {
        return "D" ;
    }
});

你可以这样使用我们刚创建的自定义函数helper:

<script id="shoe-template" type="x-handlebars-template">
    {{theNameOfTheHelper score}}
</script>

HTML页面输出结果为:
B

自定义块级helper

除了自定义函数helper,我们还可以添加自定义块级helper。当我们注册一个自定义块级helper时,Handlebars会自动给回调函数添加一个options对象,最为回调函数的最后一个参数。这个options对象有一个fn方法,一个hash对象和一个inverse方法。

options.fn方法:

fn方法接收一个对象(你的数据)作为参数,在自定义块级helper的模板中作为上下文使用。在模板中,你可以传递任何数据对象,如果你想使用与外层模板相同的上下文,你可以简单的传递一个this。

下面通过一个简单的例子来方便理解。下面就是我们要使用的数据对象(我们会将数组中每个对象的score数组求和,并用这个值替换score数组):

var contextObj = [{firstName: "Kapil", lastName:"Manish", score:[22, 34, 45, 67]}, {firstName: "Bruce", lastName:"Kasparov", score:[10, 34, 67, 90]}];

下面是我们用userScore这个块级helper写一个模板,关于userScore块级helper,我们将稍后定义:

<script id="shoe-template" type="x-handlebars-template">
    {{#userScore this}}
<div>{{firstName}} {{lastName}}, Your Total Score is {{score}} </div>
    {{/userScore}}
</script>

下面我们来使用Handlebars.registerHelper方法注册userScore块级helper。注意Handlebars会自动的将options对象添加到回调函数中,所以我们可以在这里直接使用:

Handlebars.registerHelper ("userScore", function (dataObject, options) {
    var templateWithInterpolatedData = "";

    for (var i = dataObject.length - 1; i >= 0; i--) {
        //求出score数组的和,并用这个值替换掉score数组
        dataObject[i].score = dataObject[i].score.reduce(function (prev, cur, index, array) {
            return prev + cur;
        });

        // dataObject的每个数组元素都会通过options.fn方法处理,options.fn方法会将数组元素的值插入到模板中对应的位置,并将生成的HTML返回
        // 希望下面的解释可以帮助你理解options.fn方法: options.fn方法就和常规的handlebars模板函数一样,拿到我们的数据对象,将这些值插入到模板中对应的位置,然后返回生成的HTML
        // 本例中如果没有调用options.fn方法, 那么未经处理的数据将被原样返回

        templateWithInterpolatedData += options.fn (dataObject[i]);

    }
    // 最后,我们将用dataObject值填充后的完整的HTML字符串返回
    return templateWithInterpolatedData;
});

输出结果为:
Bruce Kasparov, Your Total Score is 201
Kapil Manish, Your Total Score is 168

同样重要的是,一个自定义的块级helper可以在模板中的任意地方插入,并且我们可以在模板中给helper传递任意个数的参数。

下面来介绍一下options.inverse方法:

如果你用过if/else这个内建helper,你应该可以理解,其实inverse方法和fn方法正相反,它是用在块级语句的else部分的。当回调函数中的表达式符合你的逻辑真值时,你可以使用options.fn;相反的,如果表达式符合你的逻辑假值时,你可以使用options.inverse方法来解析模板中else部分的内容。

最后来说下options.hash对象:

Handlebars表达式不仅能接收字符串和变量作为参数,还能接收通过空格分隔的键值对作为参数。举例来说(注意键值对参数之间没有逗号):

{{#myNewHelper score=30 firstName="Jhonny" lastName="Marco"}}
    Show your HTML content here.
{{/myNewHelper}}

上面的Handlebars表达式中的键值对将会被自动添加到helper回调函数的hash对象中。我们可以做个验证:

Handlebars.registerHelper ("myNewHelper", function (dataObject, options) {
    // JSON.stringify 用于将dataObject对象序列化成一个数组
    console.log(JSON.stringify (options.hash));
    // 输出结果: {score:30, firstName:"Jhonny", lastName:"Marco"}
});

———————————————–分割线——————————————————-

简单介绍下另一个话题:Partials(子模板)

有时候你需要在一个大模板中套用另一个模板,这时候你可以使用Partials,下面是partials的使用语法:

{{> partialName}}

在使用partial之前同样需要注册partial:

Handlebars.registerPartial(“partialName”,你的partial的html);

partial的html和模板的html定义方法相同,在此不再赘述。一个重要的提示:partial和外部的模板享用同样的上下文。

Click here for more information

 

standard
  1. UR Brother - 2013 年 11 月 15 日 10:23 上午

    哇嘎里麻善嗯!

    回复
  2. keenwon - 2014 年 4 月 3 日 3:33 下午

    for (var i = dataObject.length – 1; i >= 0; i–) {….}

    凌乱了

    回复
    • lovecicy - 2014 年 4 月 3 日 6:14 下午

      反着循环而已啊

      回复

Have your say