摘要:而框架中最常用的兩個(gè)視圖引擎是和。實(shí)際上這些上下文對(duì)象就是會(huì)在視圖中使用到的變量。其實(shí)視圖緩存并不是緩存視圖實(shí)際上它緩存的視圖路徑。根據(jù)默認(rèn)視圖引擎將缺少拓展名的視圖文件補(bǔ)充完整。實(shí)際上存在由不同組織維護(hù)的兩個(gè)不同版本的。
前面的內(nèi)容大都是關(guān)于 Express 框架自身的內(nèi)容,包括:Express 簡(jiǎn)介、工作原理、框架特點(diǎn)。在系列的最后,我們將把注意力放到 Express 框架周邊工具鏈上。學(xué)習(xí)如果使用這些工具來(lái)拓展 Express 框架的功能。
首先,本文我們將會(huì)討論視圖模版引擎的使用。通過(guò)這些模版引擎我們能過(guò)動(dòng)態(tài)的生成 HTML 內(nèi)容。在前面我們已經(jīng)使用過(guò) EJS 并使用變量語(yǔ)法實(shí)現(xiàn)內(nèi)容的注入。但是這些內(nèi)容只是整個(gè)模版引擎部分的冰山一角。接下來(lái),將會(huì)學(xué)習(xí)到多種內(nèi)容注入方式、EJS,Pug 等模版引擎的特性。
Express 視圖特性在開(kāi)始之前,我們有必要解釋下何為視圖引擎(view engine)?視圖引擎作為編程術(shù)語(yǔ)它主要意思是指“進(jìn)行視圖渲染的模塊”。而 Express 框架中最常用的兩個(gè)視圖引擎是 Pug 和 EJS 。需要注意的是,Pug 早期的名稱(chēng)是 Jade 由于某些原因不得已改名 。
另外,Express 并沒(méi)有指定必須使用何種引擎。只要該視圖引擎的設(shè)計(jì)符合 Express API 規(guī)范,你就可以將其應(yīng)用到工程中。下面,我們看看它到底是如何工作的。
簡(jiǎn)單的視圖渲染示例下面我們通過(guò)一個(gè)簡(jiǎn)單示例回顧下 EJS 渲染過(guò)程:
var express = require("express"); var path = require("path"); var app = express(); app.set("view engine", "ejs"); app.set("views", path.resolve(__dirname, "views")); app.get("/", function(req, res) { res.render("index"); }); app.listen(3000);
在運(yùn)行代碼之前,你需要通過(guò) npm install 安裝 EJS 和 Express。在安裝完成后訪問(wèn)應(yīng)用主頁(yè)的話,程序就會(huì)尋找 views/index.ejs 文件并使用 EJS 對(duì)其進(jìn)行渲染。另外,工程中一般都只會(huì)使用一個(gè)視圖引擎,因?yàn)槎鄠€(gè)引擎會(huì)給工程引入不必要的復(fù)雜性。
復(fù)雜的視圖渲染下面我們看一個(gè)更為復(fù)雜的示例,其中會(huì)同時(shí)用到兩個(gè)視圖引擎 Pug 和 EJS:
var express = require("express"); var path = require("path"); var ejs = require("ejs"); var app = express(); app.locals.appName = "Song Lyrics"; app.set("view engine", "jade"); app.set("views", path.resolve(__dirname, "views")); app.engine("html", ejs.renderFile); app.use(function(req, res, next) { res.locals.userAgent = req.headers["user-agent"]; next(); }); app.get("/about", function(req, res) { res.render("about", { currentUser: "india-arie123" }); }); app.get("/contact", function(req, res) { res.render("contact.ejs"); }); app.use(function(req, res) { res.status(404); res.render("404.html", { urlAttempted: req.url }); }); app.listen(3000);
雖然代碼看起來(lái)比較復(fù)雜,但其實(shí)分解后步驟也還簡(jiǎn)單。下面,我們就對(duì)上面調(diào)用 render 處的代碼進(jìn)行分析:
Express 在你每次調(diào)用 render 時(shí)都會(huì)創(chuàng)建上下文對(duì)象,并且在進(jìn)行渲染時(shí)會(huì)傳入到視圖引擎中。實(shí)際上這些上下文對(duì)象就是會(huì)在視圖中使用到的變量。
Express 首先會(huì)將所有請(qǐng)求都公用的 app.local 中已存在的屬性添加視圖中。然后添加 res.locals 中的屬性并對(duì)可能與 app.local 沖突的屬性進(jìn)行覆蓋操作。最后,添加 render 調(diào)用處的屬性并且也可能進(jìn)行覆蓋操作。例如,訪問(wèn) /about 路徑時(shí),上下文對(duì)象就包含三個(gè)屬性:appname、userAgent、currentUser;訪問(wèn) /contact 路徑時(shí),上下文對(duì)象的屬性就只有 appname、userAgent ;而進(jìn)行 404 處理時(shí)上下文對(duì)象的屬性就變成了:appname、userAgent、urlAttempted 。
緊接著,我們將會(huì)設(shè)置是否啟用視圖緩存。其實(shí)視圖緩存并不是緩存視圖實(shí)際上它緩存的視圖路徑。例如,它會(huì)將 views/my_views.ejs 路徑緩存起來(lái)并綁定到 EJS 引擎上。
Express 通過(guò)兩種方式來(lái)決定是否對(duì)視圖文件進(jìn)行緩存: 文檔記錄方式:通過(guò)調(diào)用 *app.enabled("view cache")* 開(kāi)啟。在開(kāi)發(fā)模式下默認(rèn)是被禁用的,但是你可以在正式生產(chǎn)環(huán)境中開(kāi)啟。當(dāng)然,你可以通過(guò) *app.disable("view cache")* 手動(dòng)關(guān)閉。 非文檔記錄方式:根據(jù)第一步上下文中的 *cache* 對(duì)象是否為 *true* 來(lái)決定是否緩存該文件。這樣你就可以對(duì)每一個(gè)文件進(jìn)行自定義設(shè)置了。
接下來(lái),Express 會(huì)設(shè)置視圖文件名及其使用的視圖引擎。如果在第二步中已經(jīng)進(jìn)行了視圖緩存則可以直接跳到最后一步。否則,則繼續(xù)下一步。
根據(jù)默認(rèn)視圖引擎將缺少拓展名的視圖文件補(bǔ)充完整。在本例中,about 會(huì)被拓展成 about.jade ,而 contact.ejs 以及 404.html 文件會(huì)保存不變。如果你既沒(méi)有指定默認(rèn)視圖引擎也沒(méi)有明確拓展名,那么程序會(huì)出現(xiàn)崩潰。
通過(guò)文件拓展名進(jìn)行視圖引擎匹配。對(duì)于 .html 格式文件則根據(jù) app.engine("html", xx); 設(shè)置進(jìn)行匹配。
在視圖問(wèn)價(jià)夾下,查找視圖文件名對(duì)應(yīng)的文件。如果不存在則報(bào)錯(cuò)。
判斷查找到的視圖文件是否需要進(jìn)行緩存。
使用引擎對(duì)視圖文件進(jìn)行渲染并生成最終的 HTML 文件。
同時(shí)使用多個(gè)視圖引擎確實(shí)為程序增加了不必要的復(fù)雜性,好在絕大多數(shù)時(shí)候我們并不會(huì)這樣做。
Express 給客戶(hù)端默認(rèn)響應(yīng)的內(nèi)容是 HTML。雖然大多數(shù)時(shí)候這沒(méi)什么問(wèn)題,但是有時(shí)可能需要返回的是純文本、XML、JSON 等格式。此時(shí),你可以通過(guò)修改參數(shù) res.type 進(jìn)行自定義設(shè)置:
app.get(“/”, function(req, res) { ? res.type(“text”); ? res.render(“myview”, { ?? currentUser: “Gilligan” ? }); }
視圖引擎的 Express 兼容設(shè)置:Consolidate.js當(dāng)然,你可以使用更簡(jiǎn)單的 res.json
除了 EJS 和 Pug 之外,其實(shí)還有很多中模版引擎。但是這些模版引擎可能并不像 EJS 和 Pug 那樣是為 Express 專(zhuān)門(mén)設(shè)計(jì)的。此時(shí)如果需要使用這些未適配的模版引擎,我們就不得不使用 Consolidate.js 進(jìn)行封裝以期能夠兼容 Express API。而且 Consolidate.js 支持的種類(lèi)也非常多,你可以在項(xiàng)目首頁(yè)看到完整的支持列表。
假設(shè),現(xiàn)在你正是使用的引擎是與 Express 并不兼容的 Walrus。那么,下面我們看 Consolidate 是如何進(jìn)行兼容適配工作的。
首先,使用 npm install walrus consolidate 安裝相關(guān)類(lèi)庫(kù)和依賴(lài)項(xiàng),然后我們將其引入:
var express = require("express"); var engines = require("consolidate"); var path = require("path"); var app = express(); app.set("view engine", "wal"); app.engine("wal", engines.walrus); app.set("views", path.resolve(__dirname, "views")); app.get("/", function(req, res) { res.render("index"); }); app.listen(3000);
是不是很簡(jiǎn)單?只需幾行代碼我們就完成了整個(gè)適配工作。所以當(dāng)有兼容適配需求的時(shí)候,我強(qiáng)烈建議你使用 Consolidate 而不是自己悶頭干。
EJS 中你必須要了解的東西EJS 是 Express 中最簡(jiǎn)單也是最受歡迎的視圖引擎之一。它可以為字符串、HTML、純文本創(chuàng)建模版,而且他的集成也非常簡(jiǎn)單。它在瀏覽器和 Node 環(huán)境中都能正常工作。它與 Ruby 中的 ERB 與法非常的類(lèi)似。
EJS 語(yǔ)法實(shí)際上存在由不同組織維護(hù)的兩個(gè)不同版本的 EJS。雖然在功能上它們很相似,但是并不是同一個(gè)類(lèi)庫(kù)。其中 Express 中使用的 EJS 是由 TJ Holowaychuck 維護(hù)的,你可以通過(guò) npm 查找到該類(lèi)庫(kù)。另一個(gè)同名類(lèi)庫(kù)在 09 年就停止了更新且它不能在 Node 環(huán)境中運(yùn)行。
除了用做 HTML 模版之外,它還能應(yīng)用于字符串和純文本中。請(qǐng)看 EJS 是如何對(duì)下面文本模版進(jìn)行渲染的:
Hi <%= name %>! You were born in <%= birthyear %>, so that means you"re <%= (new Date()).getFullYear() - birthyear %> years old. <% if (career) { -%> <%=: career | capitalize %> is a cool career! <% } else { -%> Haven"t started a career yet? That"s cool. <% } -%> Oh, let"s read your bio: <%- bio %> See you later!
將下面的 JSON 數(shù)據(jù)傳入上面摸板中:
{ name: "Tony Hawk", birthyear: 1968, career: "skateboarding", bio: "Tony Hawk is the coolest skateboarder around." }
最終,得到的渲染結(jié)果是(假設(shè)當(dāng)前是 2015 年):
Hi Tony Hawk! You were born in 1968, so that means you’re 47 years old. Skateboarding is a cool career! Oh, let’s read your bio: Tony Hawk is the coolest skateboarder around. See you later!
該示例演示了 EJS 常用的四種語(yǔ)法:打印、打印并轉(zhuǎn)義、執(zhí)行 JS 代碼、過(guò)濾。
在 EJS 你可以使用兩種語(yǔ)法打印表達(dá)式的值:<%= expression %> 和 <%- expression %>,其中前者會(huì)對(duì)結(jié)果進(jìn)行 HTML 轉(zhuǎn)義。例如,當(dāng)傳入的 expression 值為 Express 時(shí),前者執(zhí)行的結(jié)果是 Express 而后者得到的字符串是 Express。我建議你使用前一種方式,因?yàn)樗鼮榭煽俊?/p>
同樣,EJS 還允許你 通過(guò) <% expression %> 語(yǔ)法在其中執(zhí)行 JS 表達(dá)式,并且該表達(dá)式并不會(huì)被打印出來(lái)。該特性在執(zhí)行循環(huán)和條件判斷的時(shí)候非常有用。另外,你還可以通過(guò) <% expression -%> 避免不必要的換行。
通過(guò) <%=: expression | xxx %> 語(yǔ)法,我們可以對(duì)表達(dá)式結(jié)果再進(jìn)行一次過(guò)濾處理。例如,上面我們就對(duì)表達(dá)式結(jié)果應(yīng)用了首字母大寫(xiě)過(guò)濾器。當(dāng)然,除了自帶的大量過(guò)濾器之外,你還可以進(jìn)行自定義。
在已有 EJS 文件中嵌入其他 EJS 模版這里,我做了一個(gè) EJS 的示例程序。雖然界面不是很好看,但是你能從中熟悉 EJS 的各種語(yǔ)法使用。
EJS 引擎允許你在當(dāng)前模版中使用另一個(gè) EJS 模版。這樣我們就能對(duì)整個(gè)進(jìn)行組件拆分復(fù)用。例如,將 HTML 的頭部和尾部拆分為 header 和 footer 模塊,然后在其他模版中進(jìn)行組合復(fù)用。
示例如下:首先我們創(chuàng)建 header.ejs 并拷貝代碼:
<%= appTitle %>/title> <%= appTitle %>
緊接著創(chuàng)建 footer 組件 footer.ejs 并拷貝代碼:
最后,我們通過(guò) include 語(yǔ)法進(jìn)行組件嵌入操作:
<% include header %>Welcome to my page!
This is a pretty cool page, I must say.
<% include footer %>
假設(shè),你現(xiàn)在需要實(shí)現(xiàn)一個(gè)展示用戶(hù)信息的組建,那么你可以創(chuàng)建 userwidget.ejs 文件并拷貝:
那么,在渲染當(dāng)前用戶(hù)時(shí)可以這樣使用該模版:
<% user = currentUser %> <% include userwidget %>
或者在渲染用戶(hù)列表時(shí):
<% userList.forEach(function(user) { %> <% include userwidget %> <% } %>
通過(guò) EJS 中的 include 語(yǔ)法,我們可以在創(chuàng)建模版的同時(shí)將其作為組件進(jìn)行子視圖的渲染操作。
添加你自己的過(guò)濾器Express 內(nèi)置的 22 個(gè)過(guò)濾器,其中包括對(duì)數(shù)組和字符串的常用操作。通常情況下,它們能過(guò)滿足你的需求,但是有時(shí)你不得不添加自己的過(guò)濾器。
假設(shè),現(xiàn)在你已經(jīng)引入了 EJS 模塊并將其保存到名為 ejs 變量中。那么你可以為按照下面的方式為 ejs.filters 拓展一個(gè)用于數(shù)組求和的過(guò)濾器。
ejs.filters.sum = function(arr) { var result = 0; for (var i = 0; i < arr.length; i++) { result += arr[i]; } return result; };
然后,你就可以在代碼中使用該過(guò)濾器了:
<%=: myarray | sum %>
實(shí)現(xiàn)和使用都非常簡(jiǎn)單,所以我建議你將那些常用操作實(shí)現(xiàn)為過(guò)濾器。
Pug 中你必須要了解的東西像 Handlebars ,Mustache ,以及 EJS 這樣的視圖引擎只是在 HTML 拓展了新語(yǔ)法它并沒(méi)有對(duì) HTML 語(yǔ)法造成破壞。對(duì)于一個(gè)了解 HTML 語(yǔ)法的設(shè)計(jì)師來(lái)說(shuō)這最好不過(guò)了,畢竟不用學(xué)習(xí)新語(yǔ)言。同樣它們還適用于非 HTML 模版環(huán)境,而這一點(diǎn)則是 Pug 的軟肋。
但是 Pug 也有自己獨(dú)特的優(yōu)勢(shì)。它能減少你的代碼量,而且代碼風(fēng)格也非常不錯(cuò)。尤其在寫(xiě) HTML 模版時(shí),標(biāo)簽會(huì)嵌套縮進(jìn)而且無(wú)需閉合。另外,EJS 風(fēng)格的判斷和循環(huán)語(yǔ)法也是內(nèi)置的。雖然需要學(xué)的東西比較多,但是它的功能也異常強(qiáng)大。
Pug 語(yǔ)法像 HTML 這樣的語(yǔ)言是嵌套的,其中有根元素()以及各種子元素(像
和 ),而子元素還可以進(jìn)一步嵌套其他元素。另外,HTML 的元素必須像 XML 一樣需要閉合。而 Pug 則采用了不同的縮進(jìn)語(yǔ)法。下面的代碼就展示了使用 Pug 實(shí)現(xiàn)的簡(jiǎn)單 web 頁(yè)面:
doctype html html(lang="en") head title Hello world! body h1 This is a Pug example #container p Wow.
上面的代碼中內(nèi)容將被轉(zhuǎn)變?yōu)橄旅娴?HTML。
Hello world! This is a Pug example
Wow.
你可以去 Pug 項(xiàng)目主頁(yè)去查看它時(shí)如何實(shí)現(xiàn)這種轉(zhuǎn)變的。
Pug 的布局布局時(shí)所有模版語(yǔ)言的一個(gè)重要特性。它可以讓我們實(shí)現(xiàn)公共組件然后在其他文件中實(shí)現(xiàn)復(fù)用。例如,我們可以將頁(yè)面的 header 和 footer 抽離出來(lái)。這樣不僅可以保證所有頁(yè)面的 header 和 footer 內(nèi)容的一致,而且修改起來(lái)也更加方便。
Pug 布局的實(shí)現(xiàn)步驟大致如下:
第一步,為所有頁(yè)面定義一個(gè)主布局文件,而該文件幾乎就是一個(gè)空模版。它用 block 語(yǔ)法進(jìn)行占位操作,然后實(shí)際生成的頁(yè)面會(huì)使用內(nèi)容替換這些占位符。示例如下:
doctype html html head meta(charset="utf-8") title Cute Animals website link(rel="stylesheet" href="the.css") block header body h1 Cute Animals website block body
你可以看到上面定義了 header 和 body 兩個(gè)占位符。下面我們將它保存到 layout.jade 文件中。緊接著我們實(shí)現(xiàn)其中的 body 塊:
extends layout.jade block body p Welcome to my cute animals page!
layout.jade 將會(huì)被渲染成:
Cute Animals website Cute Animals website
Welcome to my cute animals page!
注意到當(dāng)你拓展主布局時(shí),并不一定需要實(shí)現(xiàn)其中的所有占位塊。例如上面就沒(méi)有實(shí)現(xiàn) header 。
在其他頁(yè)面可以對(duì) body 塊進(jìn)行不同的實(shí)現(xiàn):
extends layout.jade block body p This is another page using ths layout. img(src="cute_dog.jpg" alt="A cute dog!") p Isn"t that a cute dog!
Pug 通過(guò)布局進(jìn)行組件分離讓我們可以避免一些重復(fù)的代碼。
Pug 的 Mixins 功能Pug 中還有一個(gè)被稱(chēng)為 Mixins 的酷炫特性。通過(guò)該特性你可以對(duì)文件中可能需要反復(fù)使用的功能進(jìn)行一次定義。下面,我們就通過(guò)該特性對(duì)前面 EJS 部分用戶(hù)信息展示的功能進(jìn)行重新實(shí)現(xiàn):
mixin user-widget(user) .user-widget img(src=user.profilePicture) .user-name= user.name .user-bio= user.bio // 展示當(dāng)前用戶(hù) +user-widget(currentUser) // 展示用戶(hù)列表 - each user in userList +user-widget(user)
Pug 的基礎(chǔ)內(nèi)容到此為止,更多語(yǔ)法細(xì)節(jié)請(qǐng)查看官方文檔。
總結(jié)這章的內(nèi)容包括:
Express 的視圖系統(tǒng),以及它是如何進(jìn)行動(dòng)態(tài)渲染的。
EJS 引擎的語(yǔ)法和基本使用。
Pug 引擎的語(yǔ)法和基本使用。
原文地址
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/84846.html
摘要:一些與一起使用的流行模板引擎是和,應(yīng)用程序生成器使用作為其默認(rèn)值,但它也支持其他幾個(gè)。有關(guān)可與一起使用的模板引擎列表,請(qǐng)參閱模板引擎,另請(qǐng)參閱比較模板引擎等。,使用的模板引擎,例如,要使用模板引擎。 使用模板引擎 模板引擎使你可以在應(yīng)用程序中使用靜態(tài)模板文件,在運(yùn)行時(shí),模板引擎用實(shí)際值替換模板文件中的變量,并將模板轉(zhuǎn)換為發(fā)送到客戶(hù)端的HTML文件,這種方法可以更輕松地設(shè)計(jì)HTML頁(yè)面。...
摘要:同樣的的框架中也有被稱(chēng)為中間件概念。所以,整個(gè)工作流有兩種可能情形另外,這些中間件函數(shù)中部分函數(shù)需要對(duì)響應(yīng)做出響應(yīng)。擴(kuò)展和在原來(lái)基礎(chǔ)上對(duì)和對(duì)象進(jìn)行了功能擴(kuò)展。除了對(duì)響應(yīng)對(duì)象進(jìn)行了拓展之 Express 框架的初衷是為了拓展 Node 內(nèi)置模塊的功能提高開(kāi)發(fā)效率。當(dāng)你深入研究后就會(huì)發(fā)現(xiàn),Express 其實(shí)是在 Node 內(nèi)置的 HTTP 模塊上構(gòu)建了一層抽象。理論上所有 Express...
摘要:前言要做一個(gè)全沾的工程師,對(duì)于后端和數(shù)據(jù)庫(kù)來(lái)說(shuō),即使不認(rèn)識(shí)也要見(jiàn)個(gè)面的?;玖私獾母拍罹秃?,主要是安裝上數(shù)據(jù)庫(kù),并進(jìn)行簡(jiǎn)單的增刪操作。 前言:要做一個(gè)全沾的工程師,對(duì)于后端和數(shù)據(jù)庫(kù)來(lái)說(shuō),即使不認(rèn)識(shí)也要見(jiàn)個(gè)面的。本文給的例子很簡(jiǎn)單,也貼出來(lái)源碼,只要一步步下來(lái),就可以跑起來(lái)啦~~~ 思考一個(gè)需求:做一個(gè)登錄頁(yè)面,自己搭建服務(wù)和數(shù)據(jù)庫(kù),將用戶(hù)輸入的登錄信息保存到數(shù)據(jù)庫(kù)如何完成呢:首先選擇...
摘要:應(yīng)用程序生成器使用應(yīng)用程序生成器工具快速創(chuàng)建應(yīng)用程序框架。生成的應(yīng)用程序具有以下目錄結(jié)構(gòu)生成器創(chuàng)建的應(yīng)用程序結(jié)構(gòu)只是構(gòu)建應(yīng)用程序的眾多方法之一,隨意使用此結(jié)構(gòu)或修改它以最好地滿足你的需求。 Express應(yīng)用程序生成器 使用應(yīng)用程序生成器工具express-generator快速創(chuàng)建應(yīng)用程序框架。 express-generator包安裝了express命令行工具,使用以下命令執(zhí)行此操...
摘要:相關(guān)的網(wǎng)站開(kāi)發(fā)有這么常用的四款數(shù)據(jù)層視圖層控制層框架,我們今天說(shuō)一下阿里的框架是一個(gè)自身功能極簡(jiǎn),完全是由路由和中間件構(gòu)成一個(gè)的開(kāi)發(fā)框架安裝創(chuàng)建一個(gè)目錄通過(guò)命令為你的應(yīng)用創(chuàng)建一個(gè)文件。修改請(qǐng)求和響應(yīng)對(duì)象。注意只對(duì)使用或加載的中間件有效。 express express相關(guān)的網(wǎng)站*http://expressjs.com/*http://www.expressjs.com.cn/*htt...
閱讀 721·2021-11-22 13:52
閱讀 1531·2021-09-27 13:36
閱讀 2833·2021-09-24 09:47
閱讀 2192·2021-09-22 15:48
閱讀 3609·2021-09-22 15:39
閱讀 1474·2019-08-30 12:43
閱讀 2928·2019-08-29 18:39
閱讀 3197·2019-08-29 12:51