Handlebars模板庫簡單介紹
Handlebars是JavaScript一個語義模板庫,通過對view(模板)和data(ajax請求的數據,一般是json)的分離來快速構建Web模板。它采用"Logic-less template"(無邏輯模版)的思路,在加載時被預編譯(先對view進行編譯生成模板,之后只要把json數據套進去就行了),而不是到了客戶端執行到代碼時再去編譯,這樣可以保證模板加載和運行的速度。Handlebars兼容Mustache,你可以在Handlebars中導入Mustache模板。
Handlebars expressions是handlebars模板中最基本的單元,使用方法是加兩個花括號{{value}}, handlebars模板會自動匹配相應的數值,對象甚至是函數。
當你想要復用模板的一部分,或者將長模板分割成為多個模板方便維護時,partials就派上用場了。
通過{{}}取出來的內容(把json的數據取到后,顯示在模板中時),都會經過編碼,也就是說,如果取出的內容中包含html標簽,會被轉碼成純文本,不會被當成html解析,實際上就是做了類似這樣的操作:把<用<替代。這樣做是很好的,既可以顯示html代碼(轉碼后的html),又可以避免xss注入(避免顯示的內容是script,或者href,img等有跨站腳本攻擊的標簽)。這個功能在做代碼展示的時候是非常有用的。但是有時候我們可能需要解析html,不要轉碼,很簡單,把{{}}換成{{{}}}就可以啦。
Handlebars模板庫簡單使用
<!DOCTYPE html>
<html>
<head>
<title>Handlebars Expressions Example</title>
</head>
<body>
<h1>Handlebars Expressions Example!</h1>
<div id="list">
</div>
<script type="text/javascript" src="script/jquery.js"></script> //引入jquery插件
<script type="text/javascript" src="script/handlebars-1.0.0.beta.6.js"></script> //引入handlebars模板庫
<script id="people-template" type="text/x-handlebars-template"> //顯示在頁面上的標准模板
{{#each people}}
<div class="person">
<h2>{{first_name}} {{last_name}}</h2>
<div class="phone">{{phone}}</div>
<div class="email"><a href="mailto:{{email}}">{{email}}</a></div>
<div class="since">User since {{member_since}}</div>
</div>
{{/each}}
</script>
<script type="text/javascript">
$(document).ready(function() { //頁面加載完成后,執行
var template = Handlebars.compile($("#people-template").html());
//先取到標准模板庫的元素,然后調用html方法,得到它的內容。由於它的內容是一個handlebars模板,所以可以用Handlebars.compile對這個模板進行預編譯。這里講下jQuery對象html方法:$().html(),取第一個匹配元素的內容。$().html("chaojidan"),設置所有匹配元素的內容。$().html(function(index,content){ return newContent; }) ,index是匹配元素的位置,content是匹配元素的內容,newContent是替換匹配元素內容的新內容。
var data = { //后台通過ajax請求到的數據
people: [
{ first_name: "Alan", last_name: "Johnson", phone: "1234567890", email: "alan@test.com", member_since: "Mar 25, 2011" },
{ first_name: "Allison", last_name: "House", phone: "0987654321", email: "allison@test.com", member_since: "Jan 13, 2011" },
{ first_name: "Nick", last_name: "Pettit", phone: "9836592272", email: "nick@test.com", member_since: "Apr 9, 2009" },
{ first_name: "Jim", last_name: "Hoskins", phone: "7284927150", email: "jim@test.com", member_since: "May 21, 2010" },
{ first_name: "Ryan", last_name: "Carson", phone: "8263729224", email: "ryan@test.com", member_since: "Nov 1, 2008" }
]
};
$('#list').html(template(data)); //把data對象傳進去,模板會自動去匹配數據。模板中取得是data.people屬性的值。並且對people循環處理,然后把people數組中的每一項進行輸出。最后顯示在頁面中。
});
</script>
</body>
</html>
web 開發中,js 解析JSON 是經常的事情。非常繁瑣。handlebars 使用了模版,只要你定義一個模版,提供一個json對象,handlebars 就能把json對象放到你定的模版中,非常方便好用!
在模板中也可以使用if語句,if 使用方法很簡單,只需要在template中添加{{if}}, 如果有else,也一樣,添加{{else}}。Template中代碼如下:
{{#each people}}
<div class="person">
<p>{{title}}
{{#if author}} //people數組中的每一項,如果有author屬性,就進入if語句,顯示以下html
{{author.first_name}} {{author.last_name}}</p>
{{else}} //沒有就顯示以下html
Unknown Author</p>
{{/if}}
</div>
{{/each}}
javascript模板引擎恰恰就是為了幫助我們有效的組織數據及其展示內容而出現的。和其它的模板使用方式一樣,你需要做如下兩個事情:
1. 創建展示模板 var myTemplate = Handlebars.compile($("#table-template").html()); $("#table-template").html()為模板內容
2. 將數據解析到模板中 $('#tableList').html(myTemplate(data)); myTemplate(data)為模板和數據生成的html
我們可以使用with塊去定位我們需要的celebrity屬性:
如果我們有一個這樣的上下文對象:
var shoesData = {groupName:"Celebrities", celebrity:{firstName:"Mike", lastName:"Alexander" } };
<script id="shoe-template" type="x-handlebars-template">
{{groupName}} Group
{{#with celebrity}} //進入到celebrity的上下文
<li>{{firstName}} {{lastName}}</li>
{{/with}}
</script>
下面的代碼表明了怎樣在Handlebars模板中添加注釋:
{{! 在這其中的注釋表達式不會被輸出 }}
你也可使使用一般的HTML注釋,但是它們會被輸出到HTML頁面源文件中,就像一般的HTML注釋一樣:
<!-- Regular HTML comments will be in the output -->
Handlebars可以使用../來查詢當前上下文中的父路徑的屬性。比如,有一個數據對象如下:
var shoesData = {groupName:"Celebrities", users:[{name:{firstName:"Mike", lastName:"Alexander" }}, {name:{firstName:"John", lastName:"Waters" }} ]};
我們可以使用父路徑 ../ 來得到groupName屬性:
<script id="shoe-template" type="x-handlebars-template">
{{#users}} //此種方法也會把users數組中的每一項也輸出
<li>{{name.firstName}} {{name.lastName}} is in the {{../groupName}} group.</li> //父路徑下的groupName屬性
{{/users}}
</script>
unless輔助函數可以增強if,else。下面的代碼意思:只有當userLoggedIn屬性被檢查為假值是其中的內容才會被渲染:
最后講一下Handlebars最重要的使用方法:
Handlebars.js自定義輔助函數
Handlebars允許我們添加我們自己的自定義輔助函數,有了自定義輔助函數,我們可以添加任意的Javascript邏輯。我們需要在所有的Handlebars JS代碼之前注冊自定義輔助函數。自定義輔助函數在Javascript代碼中被創建,而不是在Handlebars模板中。
你可以創建兩種自定義輔助函數:自定義輔助函數(function helper),它不要使用塊表達式就能運行,自定義塊輔助函數,它需要和一個塊表達式一起運行。
自定義函數輔助函數(function helper)
首先,我們必須用Handlebars.registerHelper方法注冊一個自定義輔助函數。這個方法接收一個字符串(輔助函數的名字)作為第一個參數,一個具有任意參數個數的函數作為第二個參數。
Handlebars.registerHelper ("theNameOfTheHelper", function (theScore) {
if (theScore >= 90) {
return "A" ;
}
else if (theScore >= 80 && theScore < 90) {
return "B" ;
}
else if (theScore >= 70 && theScore < 80) {
return "C" ;
}
else {
return "D" ;
}
});
下面是一個使用我們剛才創建的自定義函數輔助函數的Handlebars模板:
<script id="shoe-template" type="x-handlebars-template">
{{#theNameOfTheHelper score}}
</script>
下面是數據var contextObj = {score:85, userName:"Mike"};
最后,把score=85,傳入到自定義函數中,返回B。於是模板最終結果返回一個"B"。
自定義塊輔助函數
當我們注冊了一個自定義塊輔助函數時,Handlebars自動在回調函數中添加了一個可選擇對象作為最后一個參數。這個可選擇對象擁有一個fn方法,一個hash對象,以及一個inverse方法。fn方法接收一個對象(你的數據dataObject[i])作為自定義塊表達式模板(<div>{{firstName}} {{lastName}}, Your Total Score is <strong>{{score}}</strong> </div>)中的上下文。你也可以傳遞任何數據對象,或者如果你想使用引用模板同樣的上下文,你可以使用this(dataObject也就是contextObj)。
我們使用Handlebars.registerHelper注冊一個userScore的塊輔助函數。注意到參數中的最后一個項目是可選擇對象,它由Handlebars自動添加:
Handlebars.registerHelper ("userScore", function (dataObject, options) {
var templateWithInterpolatedData = "";
for (var i = dataObject.length - 1; i >= 0; i--) { //遍歷dataObject數組
dataObject[i].score = dataObject[i].score.reduce(function (prev, cur, index, array) {
return prev + cur; //數組中的每一項的score屬性是一個數組,把這個數組的每一項相加,結果返回給score屬性
});
//這里我先介紹一下數組的reduce方法:reduce方法接受兩個參數,一個回調方法,一個初始值。callback回調方法接受4個參數:之前值、當前值、索引值以及數組本身。initialValue(初始值)參數可選,表示初始值。若指定,則當作最初使用的previous值;如果缺省,則使用數組的第一個元素作為previous初始值,同時current往后排一位,相比有initialValue值少一次迭代。reduce方法,會把數組的每項進行迭代,最終的結果就是最后return的值。比如:var sum = [1, 2, 3, 4].reduce(function (previous, current, index, array) {return previous + current;});因為沒有初始值,所以previous就是數組的第一項,current就是數組的第二項,index值就是當前值的index(當前是1),array就是原數組[1,2,3,4]。第一次返回1+2=3,第二次previous等於上一次返回的值3,current等於當前值3,返回6,第三次previous等於6,當前值4,返回10.這時數組循環結束,把最后的返回結果10,返回給sum(數組調用reduce的結果)。 最終得到的結果就是數組的總和。
// dataObject[i]變成了{firstName: "Kapil", lastName:"Manish", score:201}
templateWithInterpolatedData += options.fn (c);
//將會把對象的數據插入到模板中,也就是把{firstName: "Kapil", lastName:"Manish", score:201}插入到:<div>{{firstName}} {{lastName}}, Your Total Score is <strong>{{score}}</strong> </div>,最后疊加成一個字符串
}
return templateWithInterpolatedData; //把所有的數據對象插入到模板后生成的html字符串返回。
});
數據:var contextObj = [{firstName: "Kapil", lastName:"Manish", score:[22, 34, 45, 67]}, {firstName: "Bruce", lastName:"Kasparov", score:[10, 34, 67, 90]}];
模板:
<script id="shoe-template" type="x-handlebars-template">
{{#userScore this}} //執行userScore(contextObj)
<div>{{firstName}} {{lastName}}, Your Total Score is <strong>{{score}}</strong> </div>
{{/userScore}}
</script>
最終的結果:
HTML的輸出結果是:
Bruce Kasparov, Your Total Score is 201
Kapil Manish, Your Total Score is 168
options.inverse方法:
inverse方法在任意塊表達式總被當做else部分來使用。因此,當回調函數中的表達式為一個真值是你可以使用options.fn來返回。但是當回調函數中的表達式為假值時你可以使用options.inverse(去渲染else部分中的內容)。
options.hash對象:
Handlebars表達式不接收任何字符串和變量作為參數,但是你依然可以傳遞用空格分開的鍵-值對。例如:
(注意到這里沒有逗號來分開鍵-值對變量,是空格)
{{#myNewHelper score=30 firstName="Jhonny" lastName="Marco"}}
Show your HTML content here.
{{/myNewHelper}}
調用擁有鍵-值對作為參數的Handlebars表達式將會自動添加到輔助函數回調函數的options.hash對象上。因此:
Handlebars.registerHelper ("myNewHelper", function (dataObject, options) {
//JSON.stringify用於序列化一個json對象為一個字符串
console.log(JSON.stringify (options.hash));
//輸出結果為:{score:30, firstName:"Jhonny", lastName:"Marco"}
});
加油!