Handlebars

和 Mustache 一樣是模板語言,和 Mustache 相容性高,又比 Mustache 多了一些功能。

使用模版語言的優點是語意化,開發者可以透過模板就輕易了解文件的脈絡,而不需在邏輯內打轉,另一點則是邏輯和畫面分離,開發者想要改變資料只需專注資料修改即可,無須更動連接資料與畫面的邏輯。

相對的模板語言也有缺點,首先是學習和溝通成本,開發團隊必須人人多具備模板語言框架的知識,看得出來並不等於寫得出來。另一點則是輔助工具的支援度,舉例來說,除非另外開發,否則我們的編輯器不會替模板的標籤上色、或沒有 Snippet 可用,這些可能會讓便利性降低。

基本用法

大致分三步驟:

定義模板字串

{{}} 的內容是被 Handlebars 編譯器給 escape 的,變成純粹的文字,不會被解析成 HTML 模板,因此用來置入 Javascript 變數或程式碼。

1
2
3
4
// 在這裡只是字串
var templateString = `<p>My name is {{name}}. I am {{age}} years old.</p>`;
// 字串被編譯為模板
var template = Handlebars.compile(templateString);

加入資料

變數以物件的形式被塞入 {{}} 內。

1
var data = template({name: 'Dudi', age: 47});

插入 HTML

1
document.querySelector('#dudi-profile').innerHTML = data;

細節補充

{{}}{{{}}}

前面有提到透過 {{}} 出去的內容會完全被編譯器 escape ,帶有意義的符號例如 <> 等會被轉換成純粹的字串,不會對最後的內容有任何排版的影響。

{{{}}} 的內容則不會被 escape 。以下舉例

1
2
3
4
<script>
{{{<img src="logo.png">}}} // 編譯結果: 真的是一張圖
{{<img src="logo.png">}} // 編譯結果: <img src="logo.png">
</script>

Inline-Template

也能用帶有 Handlebars 自定義 type<script> 區塊來定義模板:

1
2
3
4
<script id="intro" type="text/x-handlebars-template">
<p>My name is {{name}}</p>
<p>I am {{age}} years old.</p>
</script>

一樣用 Handlebars 提供的編譯器編譯:

1
2
3
4
<script>
var todoText = document.querySelector('#todo-template').innerHTML;
var template = Handlebars.compile(todoText);
</script>

後面加入資料和插入 HTML 的過程都雷同。

Helper

Helper 讓我們可以在模板內實現一些簡單的邏輯,或者提供一些預生成組件的方式,讓我們不需要重工刻一堆一樣的模板。 Handlebars 有自定義一些 Helpers ,也提供自訂 Helper 的方法。

以下自訂了一個 Helper,該 Helper 可以生成一段顯示住處的文字。

1
2
3
4
5
6
7
8
9
<script>
Handlebars.registerHelper('showHome', function(name, home) {
var name = Handlebars.Utils.escapeExpression(name);
var home = Handlebars.Utils.escapeExpression(home);

var homeStatement = `<p>${name} lives in ${home}.</p>`;
return new Handlebars.SafeString(homeStatement);
});
</script>

以下是使用該 Helper 的方式:

1
2
3
<script type="text/x-handlebars-template">
{{showHome 'Dudi' 'Dog House'}}
</script>

自訂 Helper 只有幾個重點:

使用 Handlebars.Utils.escapeExpression(parameter) 將參數從編譯中 escape 掉,變成單純的文字。
使用 Handlebars.SafeString(result) 讓輸出不會被 escape ,擁有我們希望擁有的功能。

Block Helper

區塊形式的 Helper 可以在模板內隔出一塊空間,讓該空間內的內容只為 Helper 所使用。 Handlebars 提供的 each Helper 就是一種。

1
2
3
4
5
6
7
<script id="todo-template" type="text/x-handlebars-template">
<ol>
{{#each todos}}
<li>{{todo}}</li>
{{/each}}
</ol>
</script>

Block Helper 用 {{#<Helper Name> }} 開頭、 {{/<Helper Name> }} 結尾。中間元素則由 Helper 的邏輯而定。像這裡就是 Iteration ,會把 todos 陣列內所有的 todo 都 loop 一次,以清單的方式顯示出來。

Pre-compile

Handlebars 還提供 Pre-compile 功能,主要目的是為了效能,在實際執行前就先編譯過一次,要灌 runtime 才能用。

小記

在寫這篇的時候,發現 Hexo 會解析雙大括號,因此把雙大括號放在 ` 內會解析錯誤,此時可以用 <code></code> 的方式包住單行的雙大括號來避開解析錯誤…

Resources

Official Docs
How template engine works
Fun Fun Function
Derek’s Handlebar Tutorial