概述
剛接觸前端的時候,師傅就給我推薦了Handlebars,自己也蠻喜歡它的語法。到現在,Handlebars都已經更新到3.0.3了,是時候重新過一遍文檔了。
引入
要使用Handlebars,首先你得download,然后再頁面引入,就像這樣
<script src="script/lib/jquery.js"></script>
<script src="script/lib/handlebars.js"></script>
如果你使用了模塊化的管理工具,如requirejs、webpack、seajs,不用擔心。Handlebars是支持amd、cmd規范的,使用就像這樣
var Handlebars=require('Handlebars');
基本
來一個簡單的例子,向服務器發起了一個ajax請求獲取了一個對象數組,要渲染到頁面上。數據格式是這樣的
var data = [
{
name: 'xxx',
age: 10
},
{
name: 'zzz',
age: 12
},
{
name: 'yyy',
age: 9
}
];
首先我們要建立一個模板結構,也就是我們的Html,為了展示和邏輯分離,我們不應該將模版內容放到js當中,先看下不好的做法:
var $container = $('#container');//容器
var content = '';
data.forEach(function (item) {
content += '<p>' + item.name + ':' + item.age + '</p>';
});
$container.html(content);
當Html內容一多,各種單引號,雙引號,可讀性、結構性太差。維護起來將是我們開發的噩夢。
使用Handlebars,首先我們將Html抽出來,就像用script標簽包裹起來,放入我們當前的頁面中,就像這樣
<body>
<div id="container"></div>
<script type="text/x-handlebars-template" id="template-user"></script>
<script src="script/lib/jquery.js"></script>
<script src="script/lib/handlebars.js"></script>
<script src="script/my/basicuse.js"></script>
</body>
記得改變type類型,這樣瀏覽器就不會把標簽里的內容當作js執行。然后編寫我們的代碼
var $container = $('#container');//容器
var source = $('#template-user').html();//獲取到html結構
var template = Handlebars.compile(source);//編譯成模板
var html = template(data);//生成完成的html結構
$container.html(html);//插入dom
Handlebars的基本使用就如上了,用{{ }}輸出內容。記住了
模板最外層的this就是你調用template方法時傳入的對象
Block
我們使用模板一般都是為了遍歷對象結構,然后渲染到頁面上。有人說了如果我就傳遞個字符串進去呢?直接
$container.html(str);
用JBM模板!使用模板最常用的就是if判斷和each遍歷了,下面來詳細講解。
Handlebars的block都是這種{{#each}}{{/each}}的閉合結構
if/unless
if
Handlebars的if判斷只能判斷true和false,沒辦法進行這種a===3的邏輯判斷。它的設定就是如此,它認為邏輯判斷的內容不應該出現在模板中。看個例子
#template {{#if isEdit}} <p>isEdit</p> {{/if}}{{#if email}} <p>{{email}}</p> {{/if}}{{#if num}} <p>{{num}}</p> {{/if}} #數據 var data = { isEdit: true, email: '', num: '0' }; #頁面效果 isEdit 0
Handlebars if在判斷前會做類型轉換,如''、undefined、null、0、[]等都會被識別為false。而實際情況下我們都用數字來標識不同的狀態,碰到這種數據我們需要預處理下,才能渲染哦。
if else
#template {{#if isEdit}} <p>isEdit</p> {{else}} <p>isNotEdit</p> {{/if}} #數據 var data = { isEdit: false }; #頁面效果 isNotEdit
看看多分支是咋子寫的
#template {{#if isEdit}} <p>isEdit</p> {{else if isRead}} <p>isNotEdit isRead</p> {{else}} <p>isNotRead</p> {{/if}} #數據 var data = { isEdit: false, isRead: false }; #頁面效果 isNotRead
unless
作用剛好跟if相反,if是true的時候返回,unless是false的時候返回,看例子
#template {{#unless isEdit}} <p>isNotEdit</p> {{else unless isRead}} <p>isRead</p> {{else}} <p>isNotRead</p> {{/unless}} #數據 var data = { isEdit: true, isRead:true }; #頁面效果 isNotRead
each
遍歷數組
#template {{#each this}} <p>{{this.name}}:{{this.age}}</p> {{else}} <p>no data</p> {{/each}} #數據 var data = [ { name: 'yyy', age: 23 }, { name: 'zzz', age: 55 } ]; #頁面效果 yyy:23 zzz:55
each也支持else的判斷。each里面的this是指向單個對象的,這個時候this可以省略不寫,效果是一樣的
{{#each this}} <p>{{name}}:{{age}}</p> {{/each}}
遍歷數組的時候一般都會輸出序號,怎么破?
#template {{#each this}} <p>{{this.name}}:{{this.age}}</p> {{/each}} #頁面效果 0 yyy:23 1 zzz:55
通過@index或者@key都可以獲得序號,但是序號都是從0開始的,這個比較坑!如果要從1開始,得自己寫個helper處理,真實日了狗了!
遍歷數組的需要判別是第一個還是最后一個怎么破?
#template {{#each this}} <p>{{name}}:{{age}}{{#if @first}}first{{/if}}{{#if @last}}last{{/if}}</p> {{/each}} #頁面效果 yyy:23 first zzz:55 last
通過@first和@last可以判斷是否是數組的第一個或者最后一個。
如果在加上@odd、@even就完美了!
遍歷對象
真實的應用場景下,服務器很可能會返回一個map,就是js當中的對象,這個時候我們是不知道有哪些key的,如何遍歷這個map呢?
#template {{#each this}} <p>{{@key}}:{{this}}</p> {{/each}} #數據 var data = { name: 'yyy', age: 23 }; #頁面效果 name:yyy age:23
通過@key可以獲取到對象的key名稱。
Html轉義
假想這樣一個場景,通過ajax獲取到了一段富文本內容,然后展示在頁面中
#template
<div>{{richText}}</div>
#數據
var data = {
richText: '<div>this is rich text</div>'
};
#頁面效果
<div>this is rich text</div>
這個時候你肯定會想了,真實日了狗了,怎么原樣輸出了,沒有解析成html啊。因為{{richText}}的輸出默認轉義Html,幾乎所有的模板引擎輸出默認都是轉義Html的,避免xss攻擊。如果你想避免轉義,請這樣用
{{{richText}}}
Helpers
列表輸出的時候,如果有時間字段,一般都需要格式化時間,拿到數據后我們還得處理
#template
{{#each this}}
<p>{{name}}:{{addTime}}</p>
{{/each}}
#js
var data = [
{
name: 'xxx',
addTime: new Date()
},
{
name: 'zzz',
addTime: new Date()
}
];
data.forEach(function(item){
item.addTime=moment(item.addTime).format('YYYY-MM-DD');
});
#頁面效果
xxx:2015-05-26
zzz:2015-05-26
換個頁面碰到類似的情景,相同的代碼又得寫一面,冗余的代碼太多了,不利於后期維護。怎么破?
#template
{{#each this}}
<p>{{name}}:{{moment addTime}}</p>
{{/each}}
#js
Handlebars.registerHelper('moment', function (date, options) {
var formatStr = options.hash.format || 'YYYY-MM-DD';
return new Handlebars.SafeString(moment(date).format(formatStr));
});
var data = [
{
name: 'xxx',
addTime: new Date()
},
{
name: 'zzz',
addTime: new Date()
}
];
注冊一個全局的moment,這樣所有的時間格式化,都可以通過{{moment time}}調用,維護的成本大大降低。
需要注意的是helper如{{moment arg1 arg2}}的形式最多添加兩個參數可以被注冊函數獲取到,如果要添加多個參數,請使用hash的形式
#template
<p>{{query name 'arg2' hash1='hash1' hash2='hash2'}}</p>
#數據
Handlebars.registerHelper('query', function (arg1, arg2, options) {
console.log('arg1:' + arg1);
console.log('arg2:' + arg2);
console.log(options.hash);
});
var data = {
name: 'jacky'
};
#控制台
$ arg1:jacky
$ arg2:arg2
$ Object {hash2: "hash2", hash1: "hash1"}
Handlebars.SafeString就是不轉義Html,如果想轉義Html直接return內容即可。
#template
<p>{{safe}}</p>
#js
Handlebars.registerHelper('safe', function () {
return new Handlebars.SafeString('<div>safe string</div>')
});
#頁面效果
safe string
Partials
共享同一個模板內容,后端渲染使用的比較多
#template
<p>{{> footer}}</p>
#js
Handlebars.registerPartial('footer', function () {
return new Handlebars.SafeString('<div>This is footer</div>')
});
var data = {
name: 'jacky'
};
#頁面效果
This is footer
../
這樣一個數據結構渲染到頁面上
#template {{#each company.prodList}} <p>{{prodName}}{{company.comName}}</p> {{/each}} #js var data = { company: { comName: '技術有限公司', prodList: [ { prodName: '產品1' }, { prodName: '產品2' } ] } }; #頁面效果 產品1 產品2
等等好像有點不對勁啊,為啥沒有公司名稱呢?前面說到each里面的this都是指向單個對象的,{{prodName}} {{company.comName}}這種寫法省略了this,還原下
{{#each company.prodList}} <p>{{this.prodName}}{{this.company.comName}}</p> {{/each}}
知道問題在哪里了吧。怎么破?
{{#each company.prodList}} <p>{{prodName}}{{../company.comName}}</p> {{/each}}
通過../回到each之外。下面來填另一個經典的坑
#template <ul> {{#each this}} <li> <ul> {{#each this}} <li>{{@../index}}-{{@index}}{{this}}</li> {{/each}} </ul> </li> {{/each}} </ul> #js var data = [ ['aaa', 'bbb', 'ccc'], ['ddd', 'eee', 'fff'] ]; #頁面效果 0-0 aaa 0-1 bbb 0-2 ccc 1-0 ddd 1-1 eee 1-2 fff
代碼鏈接
參考
概述
剛接觸前端的時候,師傅就給我推薦了Handlebars,自己也蠻喜歡它的語法。到現在,Handlebars都已經更新到3.0.3了,是時候重新過一遍文檔了。
引入
要使用Handlebars,首先你得download,然后再頁面引入,就像這樣
如果你使用了模塊化的管理工具,如requirejs、webpack、seajs,不用擔心。Handlebars是支持amd、cmd規范的,使用就像這樣
var Handlebars=require('Handlebars');
基本
來一個簡單的例子,向服務器發起了一個ajax請求獲取了一個對象數組,要渲染到頁面上。數據格式是這樣的
首先我們要建立一個模板結構,也就是我們的Html,為了展示和邏輯分離,我們不應該將模版內容放到js當中,先看下不好的做法:
當Html內容一多,各種單引號,雙引號,可讀性、結構性太差。維護起來將是我們開發的噩夢。
使用Handlebars,首先我們將Html抽出來,就像用script標簽包裹起來,放入我們當前的頁面中,就像這樣
記得改變type類型,這樣瀏覽器就不會把標簽里的內容當作js執行。然后編寫我們的代碼
Handlebars的基本使用就如上了,用{{ }}輸出內容。記住了
模板最外層的this就是你調用template方法時傳入的對象
Block
我們使用模板一般都是為了遍歷對象結構,然后渲染到頁面上。有人說了如果我就傳遞個字符串進去呢?直接
$container.html(str);
用JBM模板!使用模板最常用的就是if判斷和each遍歷了,下面來詳細講解。
Handlebars的block都是這種{{#each}}{{/each}}的閉合結構
if/unless
if
Handlebars的if判斷只能判斷true和false,沒辦法進行這種a===3的邏輯判斷。它的設定就是如此,它認為邏輯判斷的內容不應該出現在模板中。看個例子
Handlebars if在判斷前會做類型轉換,如''、undefined、null、0、[]等都會被識別為false。而實際情況下我們都用數字來標識不同的狀態,碰到這種數據我們需要預處理下,才能渲染哦。
if else
看看多分支是咋子寫的
unless
作用剛好跟if相反,if是true的時候返回,unless是false的時候返回,看例子
each
遍歷數組
each也支持else的判斷。each里面的this是指向單個對象的,這個時候this可以省略不寫,效果是一樣的
遍歷數組的時候一般都會輸出序號,怎么破?
通過@index或者@key都可以獲得序號,但是序號都是從0開始的,這個比較坑!如果要從1開始,得自己寫個helper處理,真實日了狗了!
遍歷數組的需要判別是第一個還是最后一個怎么破?
通過@first和@last可以判斷是否是數組的第一個或者最后一個。
如果在加上@odd、@even就完美了!
遍歷對象
真實的應用場景下,服務器很可能會返回一個map,就是js當中的對象,這個時候我們是不知道有哪些key的,如何遍歷這個map呢?
通過@key可以獲取到對象的key名稱。
Html轉義
假想這樣一個場景,通過ajax獲取到了一段富文本內容,然后展示在頁面中
這個時候你肯定會想了,真實日了狗了,怎么原樣輸出了,沒有解析成html啊。因為{{richText}}的輸出默認轉義Html,幾乎所有的模板引擎輸出默認都是轉義Html的,避免xss攻擊。如果你想避免轉義,請這樣用
{{{richText}}}
Helpers
列表輸出的時候,如果有時間字段,一般都需要格式化時間,拿到數據后我們還得處理
換個頁面碰到類似的情景,相同的代碼又得寫一面,冗余的代碼太多了,不利於后期維護。怎么破?
注冊一個全局的moment,這樣所有的時間格式化,都可以通過{{moment time}}調用,維護的成本大大降低。
需要注意的是helper如{{moment arg1 arg2}}的形式最多添加兩個參數可以被注冊函數獲取到,如果要添加多個參數,請使用hash的形式
Handlebars.SafeString就是不轉義Html,如果想轉義Html直接return內容即可。
Partials
共享同一個模板內容,后端渲染使用的比較多
../
這樣一個數據結構渲染到頁面上
等等好像有點不對勁啊,為啥沒有公司名稱呢?前面說到each里面的this都是指向單個對象的,{{prodName}} {{company.comName}}這種寫法省略了this,還原下
知道問題在哪里了吧。怎么破?
通過../回到each之外。下面來填另一個經典的坑