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

鍍金池/ 教程/ HTML/ 番外篇之——使用 Handlebars
第9章 增加標(biāo)簽和標(biāo)簽頁(yè)面
番外篇之——使用 Mongoose
番外篇之——使用 Async
第4章 實(shí)現(xiàn)用戶(hù)頁(yè)面和文章頁(yè)面
第12章 增加友情鏈接
第14章 增加頭像
第7章 實(shí)現(xiàn)分頁(yè)功能
第5章 增加編輯與刪除功能
第11章 增加文章檢索功能
第3章 增加文件上傳功能
番外篇之——部署到 Heroku
第2章 使用 Markdown
第13章 增加404頁(yè)面
第16章 增加日志功能
第1章 一個(gè)簡(jiǎn)單的博客
番外篇之——使用 Handlebars
第10章 增加pv統(tǒng)計(jì)和留言統(tǒng)計(jì)
番外篇之——使用 Passport
第15章 增加轉(zhuǎn)載功能和轉(zhuǎn)載統(tǒng)計(jì)
第8章 增加存檔頁(yè)面
番外篇之——使用 generic pool
番外篇之——使用 _id 查詢(xún)
番外篇之——使用 Disqus
番外篇之——使用 KindEditor
第6章 實(shí)現(xiàn)留言功能

番外篇之——使用 Handlebars

前面我們?cè)?Express 中使用的 EJS 模板引擎進(jìn)行渲染視圖和頁(yè)面的展示。當(dāng)模版文件代碼比較多且邏輯復(fù)雜時(shí),代碼就變得非常難看了,滿(mǎn)眼的 <% 和 %>。下面我們嘗試使用 Handlebars 這個(gè)模版引擎替換 EJS ,代碼會(huì)變得整潔許多。

Handlebars 是 JavaScript 一個(gè)語(yǔ)義模板庫(kù),通過(guò)對(duì) view 和 data 的分離來(lái)快速構(gòu)建 Web 模板。它采用 "Logic-less template"(無(wú)邏輯模版)的思路,在加載時(shí)被預(yù)編譯,而不是到了客戶(hù)端執(zhí)行到代碼時(shí)再去編譯,這樣可以保證模板加載和運(yùn)行的速度。Handlebars 兼容 Mustache,你可以在 Handlebars 中導(dǎo)入 Mustache 模板。

Handlebars 的語(yǔ)法也非常簡(jiǎn)單易學(xué)。這里我們不會(huì)講解 Handlebars 的語(yǔ)法,官網(wǎng)( http://handlebarsjs.com/ )的文檔非常全面。

我們使用 express-handlebars 這個(gè)第三方包添加對(duì) Handlebars 的支持。

注意:也許你會(huì)非常自覺(jué)的認(rèn)為應(yīng)該使用 npm install handlebars 安裝 Handlebars 然后開(kāi)始大刀闊斧地修改代碼。但在這里我們不使用官方提供的 Handlebars 包,Express 默認(rèn)支持的模板引擎中不包含 Handlebars ,雖然我們可以通過(guò) consolidate.js + handlebars 實(shí)現(xiàn),但仍然有一個(gè)缺點(diǎn)是不支持從一個(gè)模版文件加載另一個(gè)模版文件,而在 EJS 中可以使用 <%- include someTemplate %> 輕松實(shí)現(xiàn)。express-handlebars 包彌補(bǔ)了該缺點(diǎn),所以我們使用 express-handlebars 來(lái)完成代碼的修改。

首先,打開(kāi) package.json ,刪除 ejs 并添加對(duì) express-handlebars 的依賴(lài):

"express-handlebars": "*"

并 npm install 安裝 express-handlebars 包。

打開(kāi) 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');

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

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

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

然后打開(kāi) 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="主頁(yè)" href="/">home</a></span>
<span><a title="存檔" href="/archive">archive</a></span>
<span><a title="標(biāo)簽" 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="注冊(cè)" 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>

這里我們定義了一個(gè)默認(rèn)的頁(yè)面布局模版(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}} | 
    標(biāo)簽:
    {{#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}} | 
    評(píng)論:{{comments.length}} | 
    轉(zhuǎn)載:
    {{#if reprint_info.reprint_to}}
      {{reprint_info.reprint_to.length}}
    {{else}}
      0
    {{/if}}
  </p>
{{/each}}

這樣就可以了,現(xiàn)在運(yùn)行你的博客試試吧。

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

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

在 ejs 中,我們可以隨意使用 JavaScript 表達(dá)式,如 <% if (1 + 1 === 2) { %> ... <% } %> ,但在 Handlebars 中我們卻不能這樣寫(xiě) {{#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 %>

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

打開(kāi) 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}} 內(nèi)的 @index 表示當(dāng)前遍歷的索引。

最后,還需提醒的一點(diǎn)是:我們每次渲染一個(gè)視圖文件時(shí),都會(huì)結(jié)合 layout.hbs 然后渲染,有時(shí)候我們并不需要 layout.hbs ,比如 404 頁(yè)面,需設(shè)置為:

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

通過(guò)設(shè)置 layout: false 就取消了自動(dòng)加載 layout.hbs 頁(yè)面布局模版。

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

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