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

相關文章
相關標籤/搜索