Handlebars中文文档 - 块级helpers(译自官方版)

原文在此:original article in herejavascript

译注:
1. 通常来讲context,翻译为【上下文】,在 JS 中多数时候就是指函数执行时的 this 的引用。
2. 看,不是最重要的,多写代码,照着例子写写,再改改,看看结果,就知道怎么回事了。html


块级 helpers 使用自定义的迭代器,其余的 helpers 均可以使用一个新的上下文来执行内部的代码块。

基础

先定义一个简单的块级 helper,它只是简单的执行一下这块代码,就跟没有用这个helper同样。java

<div class="entry">
  <h1>{{title}}</h1>
  <div class="body">
    {{#noop}}{{body}}{{/noop}}
  </div>
</div>

这个 noop helper 接受一个 options 对象。这个对象有一个叫 options.fn 的方法,这个方法的用法就跟普通的编译过的 Hanldebars 模板的用法同样。所不一样的就是,这个函数执行时会带有一个上下文,而且会返回一个字符串。json

Handlebars.registerHelper('noop', function(options) {
  return options.fn(this);
});

Handlebars 在执行 helpers 的时候,老是会将 this 指向当前的上下文,因此,你只需用 this 来调用这一块代码,就能够在当前的上下文中求值了。数组

with helper

在上面介绍的 noop helper 的基础上,很容易的就能想到应该如何实现 with helper 了。这里呢,不是用当前的上下文来执行代码块,咱们可使用任意的模板所传递进来的上下文。less

<div class="entry">
  <h1>{{title}}</h1>
  {{#with story}}
    <div class="intro">{{{intro}}}</div>
    <div class="body">{{{body}}}</div>
  {{/with}}
</div>

在你使用的JSON嵌套很是深的时候,就会以为这个helper 很是有帮助了,不然的话,每次都须要先写上很长的父级属性。好比上面的模板可使用下面的这段JSON:函数

{
  title: "First Post",
  story: {
    intro: "Before the jump",
    body: "After the jump"
  }
}

实现这种helper,就跟实现一堆 noop helper 没什么区别。要注意的是,helpers 能够接受参数,而且对参数的求值就跟直接使用 {{mustache}} 表达式同样同样地。oop

Handlebars.registerHelper('with', function(context, options) {
  return options.fn(context);
});

helpers 接受参数的顺序跟传递进来的顺序相同。this

简单的迭代器

使用块级 helpers 的一个很是常见的目的就是定义一个自定义的迭代器。实际上,全部的 Handlebars 内置的 helpers 就是一些常规的 块级 helpers。咱们一块儿来看看内置的 each helper 是如何工做的:url

<div class="entry">
  <h1>{{title}}</h1>
  {{#with story}}
    <div class="intro">{{{intro}}}</div>
    <div class="body">{{{body}}}</div>
  {{/with}}
</div>
<div class="comments">
  {{#each comments}}
    <div class="comment">
      <h2>{{subject}}</h2>
      {{{body}}}
    </div>
  {{/each}}
</div>

在这里的状况下,咱们但愿对 comments 数组的每一项都执行 传递给 each 的这一块代码。

Handlebars.registerHelper('each', function(context, options) {
  var ret = "";

  for(var i=0, j=context.length; i<j; i++) {
    ret = ret + options.fn(context[i]);
  }

  return ret;
});

这样,咱们迭代传进来的参数的每个项,并在每一次迭代的时候执行一次块中的代码。在咱们迭代的过程当中,还构建了一个字符串,并最终返回这个字符串。

能够看出,你也能够很容易的实现一个更高级的迭代器。例如,咱们建立一个迭代器,能够生成 <ul> 的包裹容器,而且把每个元素的计算结果包裹到<li> 中去。

{{#list nav}}
  <a href="{{url}}">{{title}}</a>
{{/list}}

可使用相似下面的上下文来执行模板:

{
  nav: [
    { url: "http://www.yehudakatz.com", title: "Katz Got Your Tongue" },
    { url: "http://www.sproutcore.com/block", title: "SproutCore Blog" },
  ]
}

这个 helper 跟内置的 each helper 没有太大的不一样。

Handlebars.registerHelper('list', function(context, options) {
  var ret = "<ul>";

  for(var i=0, j=context.length; i<j; i++) {
    ret = ret + "<li>" + options.fn(context[i]) + "</li>";
  }

  return ret + "</ul>";
});

你固然也可使用相似 underscore.js 或 SproutCore's 的类库,让代码看起来更精简漂亮些。使用 SproutCore's 的示例以下:

Handlebars.registerHelper('list', function(context, options) {
  return "<ul>" + context.map(function(item) {
    return "<li>" + options.fn(item) + "</li>";
  }).join("\n") + "</ul>";
});

条件

使用 helpers 的另外一个常见需求就是实现条件判断。
再次重申一遍,Handlebars 内置的 ifunless 控制结构就是使用常规的 helpers 来实现的。

{{#if isActive}}
  <img src="star.gif" alt="Active">
{{/if}}

控制结构通常不会改变上下文,只是要根据一些变量来决定是否要执行这一块代码。

Handlebars.registerHelper('if', function(conditional, options) {
  if(conditional) {
    return options.fn(this);
  }
});

在写控制结构的时候,常常须要在模板中提供一块 条件求值返回false时 执行的模板代码。Handlebars 给 helpers 提供了通用的 else 功能来解决这个问题。

{{#if isActive}}
  <img src="star.gif" alt="Active">
{{else}}
  <img src="cry.gif" alt="Inactive">
{{/if}}

Handlebars 以 options.inverse 的形式来支持 else 块中的代码。若是模板没有提供条件取反的模板,Handlebars会自动的建立一个 空函数,这样你就没必要去检查 inverse 是否存在了。

Handlebars.registerHelper('if', function(conditional, options) {
  if(conditional) {
    return options.fn(this);
  } else {
    return options.inverse(this);
  }
});

Handlebars 还给 helpers 提供了额外的元数据,附加在 options 对象上面。继续阅读下面的例子。

哈希参数

就像普通的 helpers,块级 helpers 能够接受一个可选的对象做为最后一个参数。咱们一块儿重温一下 list helper,并让他能够接受任意数量的可选属性,而且把添加到咱们要建立的 <ul> 元素上。

{{#list nav id="nav-bar" class="top"}}
  <a href="{{url}}">{{title}}</a>
{{/list}}

Handlebars 以 options.hash 的形式把最后传进来的键值对挂在上来。这样就更容易接受不定数量的参数了,同时接受一个可选的对象。若是模板没有提供哈希参数,Handlebars 会自动的传一个空对象({}),这样你就没必要检查哈希参数是否存在了。

Handlebars.registerHelper('list', function(context, options) {
  var attrs = Em.keys(options.hash).map(function(key) {
    key + '="' + options.hash[key] + '"';
  }).join(" ");

  return "<ul " + attrs + ">" + context.map(function(item) {
    return "<li>" + options.fn(item) + "</li>";
  }).join("\n") + "</ul>";
});

哈希参数提供了一个强大的方法来给 helper 提供任意数量的可选参数,并且避免了由可选性致使的复杂语法。

块级helper还能够往它的子模板中注入私有变量。在一些状况下会颇有帮助,好比须要把一些不在原来上下文中的数据插进来。

例如,在循环一个列表的时候,你须要以私有变量的形式提供当前的索引index值。

{{#list array}}
  {{@index}}. {{title}}
{{/list}}
Handlebars.registerHelper('list', function(context, options) {
  var out = '

<

ul>', data;

  for (var i=0; i<context.length; i++) {
    if (options.data) {
      data = Handlebars.createFrame(options.data || {});
      data.index = i;
    }

    out += "<li>" + options.fn(context[i], { data: data }) + "</li>";
  }

  out += "</ul>";
  return out;
});

私有属性经过 data 选项来提供,而且在全部的内部做用域内均可以使用。

要保证每次带着 data 执行代码块的时候都生成一个新的 data 帧。不然的话,后面的 helpers 可能会意外的改变前面的变量。

还要确保在试图跟已存在的 data 对象交互以前 data 对象已经存在了。私有变量的行为是有条件编译的,有一些模板可能并无建立这个字段。

空白管理

模板中的空白能够忽略,mustache声明的两边均可以,只需添加一个 ~ 字符便可。写了这个以后,这一边的全部空白都会被移除,直到最近的Handlebars表达式或这一边的非空白字符。

{{#each nav ~}}
  <a href="{{url}}">
    {{~#if test}}
      {{~title}}
    {{~^~}}
      Empty
    {{~/if~}}
  </a>
{{~/each}}

用这个上下文:

{
  nav: [
    {url: 'foo', test: true, title: 'bar'},
    {url: 'bar'}
  ]
}

得出的结果没有换行,也没有格式化用的空白符:

<a href="foo">bar</a><a href="bar">Empty</a>

转载请注明来自超2真人
本文连接:http://www.peichao01.com/static_content/doc/html/introduce-handlebars-helpers.html

相关文章
相关标签/搜索