Express模版引擎hbs備忘


最近幾天折騰了下express,想找個合適的模版引擎,下面是一些折騰過程的備忘

選擇標准

選擇一門模版語言時,可能會考慮的幾點

  • 語法友好(micro tmpl那種語法真是夠了)
  • 支持模版嵌套(子模版的概念)
  • 支持模版繼承(extend)
  • 前后端共用
  • 有容錯處理(最好定位到具體出錯位置)
  • 支持預編譯(性能好)

注意到hbs,似乎滿足大部分的需求:https://github.com/donpark/hbs

getting started

demo地址:https://github.com/chyingp/blog/tree/master/demo/2015.04.01-hbs/getting-started 
目錄結構如下:

.
├── app.js ├── node_modules │ ├── express │ └── hbs ├── package.json └── views └── index.hbs

看下app.js內容,還是比較容易理解的。模版views/index.hbs沒什么好說的,語法跟handlbars一樣

var express = require('express'), hbs = require('hbs'), app = express(); app.set('view engine', 'hbs'); // 用hbs作為模版引擎 app.set('views', __dirname + '/views'); // 模版所在路徑 app.get('/', function(req, res){ res.render('index', {title: 'hbs demo', author: 'chyingp'}); }); app.listen(3000); 

模版繼承:layout.hbs

demo地址:https://github.com/chyingp/blog/tree/master/demo/2015.04.01-hbs/inherit-from-layout

如果稍微看過hbs源碼可以知道,hbs默認會到views下找layout.hbs這個模版,將這個模板作為基本骨架,來渲染返回的頁面。

getting-started里的例子來說,比如用戶請求 http://127.0.0.1:3000,那么,處理步驟如下

  1. 查找views/index.hbs,進行編譯,並將編譯的結果保存為 A
  2. 查找views/layout.hbs,如果 
    1. 存在:對layout.hbs進行編譯,其中{{{body}}}標簽替換成 A,並返回最終編譯結果B
    2. 不存在:返回A

直接看例子。目錄機構如下,可以看到多了個layout.hbs

.
├── app.js ├── node_modules │ ├── express │ └── hbs ├── package.json ├── public │ └── style.css └── views ├── index.hbs ├── layout.hbs └── profile.hbs

layout.hbs的內容如下:

<!DOCTYPE html> <html> <head> <title>{{title}}</title> <link rel="stylesheet" type="text/css" href="/style.css"> </head> <body> {{{body}}} </body> </html>

相應的,index.hbs調整為

<h1>Demo by {{author}}</h1> <p>{{author}}: welcome to homepage, I'm handsome!</p>

再次訪問 http://127.0.0.1:3000,可以看到返回的頁面

Alt text

模版繼承+自定義擴展

demo地址:https://github.com/chyingp/blog/tree/master/demo/2015.04.01-hbs/inherit-and-override

在項目中,我們會有這樣的需求。頁面的基礎骨架是共享的,但某些信息,每個頁面可能是不同的,比如引用的css文件、meta標簽等。那么,除了上面提到的“繼承”之外,還需要引入類似“覆蓋”的特性。

hbs官方其實就提供了demohttps://github.com/donpark/hbs/blob/master/examples/extend/ ,感興趣的同學可以去圍觀下。可以看到,在app.js里面加入了下面的 helper function`,這就是實現”覆蓋“ 的關鍵代碼了。

var blocks = {}; hbs.registerHelper('extend', function(name, context) { var block = blocks[name]; if (!block) { block = blocks[name] = []; } block.push(context.fn(this)); // for older versions of handlebars, use block.push(context(this)); }); hbs.registerHelper('block', function(name) { var val = (blocks[name] || []).join('\n'); // clear the block blocks[name] = []; return val; });

此外,layout.hbs需要做點小改動。里面比較明顯的變化是加入了下面的block標記

{{{block "stylesheets"}}}
 {{{block "scripts"}}}

那么,可以在index.hbs里對這些標記的內容進行覆蓋(或者說自定義),包括其他的模版,如果有需要,都可以對這兩個`block進行覆蓋。

{{#extend "stylesheets"}} <link rel="stylesheet" href="/css/index.css"/> {{/extend}} let the magic begin {{#extend "scripts"}} <script> document.write('foo bar!'); </script> {{/extend}}

那么問題來了。如果有這樣的需求:所有的頁面,都引用 style.css,只有 index.hbs 引用 index.css,那么上面的改動還不足以滿足這個需求。

其實,只需要改幾行代碼就可以實現了,擴展性點個贊。改動后的app.js如下

var blocks = {}; hbs.registerHelper('extend', function(name, context) { var block = blocks[name]; if (!block) { block = blocks[name] = []; } block.push(context.fn(this)); // for older versions of handlebars, use block.push(context(this)); }); // 改動主要在這個方法 hbs.registerHelper('block', function(name, context) { var len = (blocks[name] || []).length; var val = (blocks[name] || []).join('\n'); // clear the block blocks[name] = []; return len ? val : context.fn(this); });

 

 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM