在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ HTML/ 番外篇之——使用 Handlebars
第9章 增加標簽和標簽頁面
番外篇之——使用 Mongoose
番外篇之——使用 Async
第4章 實現用戶頁面和文章頁面
第12章 增加友情鏈接
第14章 增加頭像
第7章 實現分頁功能
第5章 增加編輯與刪除功能
第11章 增加文章檢索功能
第3章 增加文件上傳功能
番外篇之——部署到 Heroku
第2章 使用 Markdown
第13章 增加404頁面
第16章 增加日志功能
第1章 一個簡單的博客
番外篇之——使用 Handlebars
第10章 增加pv統計和留言統計
番外篇之——使用 Passport
第15章 增加轉載功能和轉載統計
第8章 增加存檔頁面
番外篇之——使用 generic pool
番外篇之——使用 _id 查詢
番外篇之——使用 Disqus
番外篇之——使用 KindEditor
第6章 實現留言功能

番外篇之——使用 Handlebars

前面我們在 Express 中使用的 EJS 模板引擎進行渲染視圖和頁面的展示。當模版文件代碼比較多且邏輯復雜時,代碼就變得非常難看了,滿眼的 <% 和 %>。下面我們嘗試使用 Handlebars 這個模版引擎替換 EJS ,代碼會變得整潔許多。

Handlebars 是 JavaScript 一個語義模板庫,通過對 view 和 data 的分離來快速構建 Web 模板。它采用 "Logic-less template"(無邏輯模版)的思路,在加載時被預編譯,而不是到了客戶端執(zhí)行到代碼時再去編譯,這樣可以保證模板加載和運行的速度。Handlebars 兼容 Mustache,你可以在 Handlebars 中導入 Mustache 模板。

Handlebars 的語法也非常簡單易學。這里我們不會講解 Handlebars 的語法,官網( http://handlebarsjs.com/ )的文檔非常全面。

我們使用 express-handlebars 這個第三方包添加對 Handlebars 的支持。

注意:也許你會非常自覺的認為應該使用 npm install handlebars 安裝 Handlebars 然后開始大刀闊斧地修改代碼。但在這里我們不使用官方提供的 Handlebars 包,Express 默認支持的模板引擎中不包含 Handlebars ,雖然我們可以通過 consolidate.js + handlebars 實現,但仍然有一個缺點是不支持從一個模版文件加載另一個模版文件,而在 EJS 中可以使用 <%- include someTemplate %> 輕松實現。express-handlebars 包彌補了該缺點,所以我們使用 express-handlebars 來完成代碼的修改。

首先,打開 package.json ,刪除 ejs 并添加對 express-handlebars 的依賴:

"express-handlebars": "*"

并 npm install 安裝 express-handlebars 包。

打開 app.js ,添加一行:

var exphbs  = require('express-handlebars');

然后將:

app.set('view engine', 'ejs');

修改為:

app.engine('hbs', exphbs({
  layoutsDir: 'views',
  defaultLayout: 'layout',
  extname: '.hbs'
}));
app.set('view engine', 'hbs');

這里我們注冊模板引擎處理后綴名為 hbs 的文件,然后通過 app.set('view engine', 'hbs'); 設置模板引擎。以上參數的意思是:

  • layoutsDir: 'views': 設置布局模版文件的目錄為 views 文件夾
  • defaultLayout: 'layout': 設置默認的頁面布局模版為 layout.hbs 文件,跟 Express 2.x 中的 layout.ejs 作用類似。
  • extname: '.hbs': 模版文件使用的后綴名,這個 .hbs 是我們自定的,我們當然可以使用 .html 和 .handlebars 等作為后綴,只需把以上的 hbs 全部替換即可。

我們以修改主頁為例,學習如何使用 Handlebars 。為了測試修改后能否正常顯示文章及其相關信息,在開始之前,我們先注冊幾個用戶并發(fā)表幾篇文章,然后進行一些互相轉載、訪問和留言等工作,而不是清空數據庫。

然后打開 views 文件夾,刪除 header.ejs 和 footer.ejs ,新建 layout.hbs ,添加如下代碼:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Blog</title>
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>

<header>
<h1>{{title}}</h1>
</header>

<nav>
<span><a title="主頁" href="/">home</a></span>
<span><a title="存檔" href="/archive">archive</a></span>
<span><a title="標簽" href="/tags">tags</a></span>
<span><a title="友情鏈接" href="/links">links</a></span>
{{#if user}}
  <span><a title="上傳" href="/upload">upload</a></span>
  <span><a title="發(fā)表" href="/post">post</a></span>
  <span><a title="登出" href="/logout">logout</a></span>
{{else}}
  <span><a title="登錄" href="/login">login</a></span>
  <span><a title="注冊" href="/reg">register</a></span>
{{/if}}
<span><form action="/search" method="GET"><input type="text" name="keyword" placeholder="SEARCH" class="search" /></form></span>
</nav>

<article>

{{#if success}}
  <div>{{success}}</div>
{{/if}}
{{#if error}}
  <div>{{error}}</div>
{{/if}}

{{{body}}}

</article>
</body>
</html>

這里我們定義了一個默認的頁面布局模版(layout.hbs)。其余所有的模版都將 "繼承" 該模版,即替換掉 {{{body}}} 部分。

刪除 index.ejs ,新建 index.hbs ,添加如下代碼:

{{#each posts}}
  <p><h2><a href="/u/{{name}}/{{time.day}}/{{title}}">{{title}}</a></h2>
  <a href="/u/{{name}}"><img src="{{head}}" class="r_head" /></a></p>
  <p class="info">
    作者:<a href="/u/{{name}}">{{name}}</a> | 
    日期:{{time.minute}} | 
    標簽:
    {{#each tags}}
      {{#if this}}
        <a class="tag" href="/tags/{{this}}">{{this}}</a>
      {{/if}}
    {{/each}}
    {{#if reprint_info.reprint_from}}
      <br><a href="/u/{{reprint_info.reprint_from.name}}/{{reprint_info.reprint_from.day}}/{{reprint_info.reprint_from.title}}">原文鏈接</a>
    {{/if}}
  </p>
  <p>{{{post}}}</p>
  <p class="info">
    閱讀:{{pv}} | 
    評論:{{comments.length}} | 
    轉載:
    {{#if reprint_info.reprint_to}}
      {{reprint_info.reprint_to.length}}
    {{else}}
      0
    {{/if}}
  </p>
{{/each}}

這樣就可以了,現在運行你的博客試試吧。

當我們渲染 index.hbs (res.render('index', { ... });)時,index.hbs 會替換 layout.hbs 中的 {{{body}}} 部分,然后渲染視圖。需要注意的是,我們在 {{#each}} ... {{/each}} 中使用了 this ,這里的 this 指向當前上下文,即代表遍歷的每一項。

注意:Handlebars 中的 {{{htmlContext}}},相當于 EJS 中的 <%- htmlContext %> ,{{textContext}} 相當于 <%= textContext %> 。

在 ejs 中,我們可以隨意使用 JavaScript 表達式,如 <% if (1 + 1 === 2) { %> ... <% } %> ,但在 Handlebars 中我們卻不能這樣寫 {{#if (1 + 1 === 2)}} ... {{/if}} ,那么該如何修改 archive.ejs 呢?archive.ejs 代碼如下:

<%- include header %>
<ul class="archive">
<% var lastYear = 0 %>
<% posts.forEach(function (post, index) { %>
  <% if (lastYear != post.time.year) { %>
    <li><h3><%= post.time.year %></h3></li>
  <% lastYear = post.time.year } %>
    <li><time><%= post.time.day %></time></li>
    <li><a href="/u/<%= post.name %>/<%= post.time.day %>/<%= post.title %>"><%= post.title %></a></li>
<% }) %>
</ul>
<%- include footer %>

我們通過定義了一個 lastYear 變量實現了判斷并只顯示一次年份的功能。在 Handlebars 中,我們可以通過 registerHelper 實現以上功能,關于 registerHelper 的使用詳見 http://handlebarsjs.com/block_helpers.html。在 express-handlebars 中使用 registerHelper 也很簡單,具體如下。

打開 index.js ,將 app.get('/archive') 修改如下:

app.get('/archive', function (req, res) {
  Post.getArchive(function (err, posts) {
    if (err) {
      req.flash('error', err); 
      return res.redirect('/');
    }
    res.render('archive', {
      title: '存檔',
      posts: posts,
      user: req.session.user,
      success: req.flash('success').toString(),
      error: req.flash('error').toString(),
      helpers: {
        showYear: function(index, options) {
          if ((index == 0) || (posts[index].time.year != posts[index - 1].time.year)) {
            return options.fn(this);
          }
        }
      }
    });
  });
});

刪除 archive.ejs ,新建 archive.hbs ,添加如下代碼:

<ul class="archive">
{{#each posts}}
  {{#showYear @index}}
    <li><h3>{{this.time.year}}</h3></li>
  {{/showYear}}
  <li><time>{{this.time.day}}</time></li>
  <li><a href="/u/{{this.post.name}}/{{this.time.day}}/{{this.title}}">{{this.title}}</a></li>
{{/each}}
</ul>

假如你了解如何使用 Handlebars 中的 registerHelper ,那么上面的代碼就很容易理解了。其中,{{#each}} ... {{/each}} 內的 @index 表示當前遍歷的索引。

最后,還需提醒的一點是:我們每次渲染一個視圖文件時,都會結合 layout.hbs 然后渲染,有時候我們并不需要 layout.hbs ,比如 404 頁面,需設置為:

res.render('404', {
  layout: false
});

通過設置 layout: false 就取消了自動加載 layout.hbs 頁面布局模版。

至此,我們通過采用 layout 的方式實現了視圖文件的加載及渲染,express-handlebars 還提供了另一種類似于 EJS 中 include 的加載方式——使用 partial ,前面的修改中我們并沒有添加分頁模版(paging.hbs),要想引入分頁模版使用 {{> paging}} 即可。詳細使用見 https://github.com/ericf/express-handlebars。

讀者可自行完成剩余的修改工作。