原文在此: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 內置的 if
和 unless
控制結構就是使用常規的 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