主頁
我們要建立的第一個頁面是網站的主頁,可以從站點 (/) 或目錄 (catalog/) 的根目錄訪問。此頁面將顯示一些描述站點的靜態文字,以及資料庫中各種記錄型別的動態計算的“計數”。
我們已經為首頁建立了一個路由。為了完成頁面,我們需要更新我們的控制器函式,從資料庫獲取記錄的“計數”,並建立一個我們可以用來渲染頁面的檢視(模板)。
注意:我們將使用 Mongoose 來獲取資料庫資訊。在繼續之前,您可能希望重新閱讀 Mongoose 基礎知識 部分中關於 搜尋記錄 的內容。
路由
我們在 上一篇教程 中建立了索引頁面的路由。提醒一下,所有路由函式都定義在 /routes/catalog.js 中。
// GET catalog home page.
router.get("/", book_controller.index); // This actually maps to /catalog/ because we import the route with a /catalog prefix
作為引數傳遞的圖書控制器索引函式 (book_controller.index) 在 /controllers/bookController.js 中定義了一個“佔位符”實現。
exports.index = async (req, res, next) => {
res.send("NOT IMPLEMENTED: Site Home Page");
};
正是這個控制器函式,我們對其進行擴充套件以從我們的模型中獲取資訊,然後使用模板(檢視)進行渲染。
控制器
索引控制器函式需要獲取有關資料庫中有多少 Book、BookInstance(全部)、BookInstance(可用)、Author 和 Genre 記錄的資訊,在模板中渲染這些資料以建立 HTML 頁面,然後將其返回到 HTTP 響應中。
開啟 /controllers/bookController.js。在該檔案的頂部附近,您應該會看到匯出的 index() 函式。
const Book = require("../models/book");
exports.index = async (req, res, next) => {
res.send("NOT IMPLEMENTED: Site Home Page");
};
用以下程式碼片段替換以上所有程式碼。這首先匯入(require())所有模型。我們需要這樣做,因為我們將使用它們來獲取文件計數。
const Book = require("../models/book");
const Author = require("../models/author");
const Genre = require("../models/genre");
const BookInstance = require("../models/bookinstance");
exports.index = async (req, res, next) => {
// Get details of books, book instances, authors and genre counts (in parallel)
const [
numBooks,
numBookInstances,
numAvailableBookInstances,
numAuthors,
numGenres,
] = await Promise.all([
Book.countDocuments({}).exec(),
BookInstance.countDocuments({}).exec(),
BookInstance.countDocuments({ status: "Available" }).exec(),
Author.countDocuments({}).exec(),
Genre.countDocuments({}).exec(),
]);
res.render("index", {
title: "Local Library Home",
book_count: numBooks,
book_instance_count: numBookInstances,
book_instance_available_count: numAvailableBookInstances,
author_count: numAuthors,
genre_count: numGenres,
});
};
我們使用 countDocuments() 方法來獲取每個模型的例項數量。此方法在模型上呼叫,帶有一個可選的匹配條件集,並返回一個 Query 物件。透過呼叫 exec() 可以執行查詢,它返回一個 Promise,該 Promise 要麼以結果兌現,要麼在發生資料庫錯誤時被拒絕。
由於文件計數查詢是相互獨立的,我們使用 Promise.all() 並行執行它們。該方法返回一個新 Promise,我們 await 它完成(在此函式內,執行在 await 處暫停)。當所有查詢完成時,由 all() 返回的 Promise 兌現,繼續執行路由處理函式,並用資料庫查詢結果填充陣列。
然後,我們呼叫 res.render(),指定一個名為 'index' 的檢視(模板),以及將資料庫查詢結果對映到檢視模板的物件。資料以鍵值對的形式提供,並且可以在模板中使用鍵進行訪問。
注意:如果您在 Pug 模板中使用了未傳遞的鍵/變數,則它將渲染為空字串,並在表示式中評估為 false。其他模板語言可能要求您傳遞用於所有使用的物件的值。
請注意,程式碼非常簡單,因為我們可以假設資料庫查詢會成功。如果任何資料庫操作失敗,丟擲的異常將導致 Promise 被拒絕,Express 會將錯誤傳遞給鏈中的 next 中介軟體處理程式。
檢視
開啟 /views/index.pug 並用以下文字替換其內容。
extends layout
block content
h1= title
p Welcome to #[em LocalLibrary], a very basic Express website developed as a tutorial example on the Mozilla Developer Network.
h2 Dynamic content
p The library has the following record counts:
ul
li #[strong Books:] !{book_count}
li #[strong Copies:] !{book_instance_count}
li #[strong Copies available:] !{book_instance_available_count}
li #[strong Authors:] !{author_count}
li #[strong Genres:] !{genre_count}
檢視很簡單。我們擴充套件了 layout.pug 基本模板,覆蓋了名為 'content' 的 block。第一個 h1 標題將是傳遞給 render() 函式的 title 變數的轉義文字——請注意 h1= 的用法,以便將後面的文字視為 JavaScript 表示式。然後,我們包含一個介紹 LocalLibrary 的段落。
在“動態內容”標題下,我們列出了每個模型的副本數量。請注意,模板中的資料值是呼叫路由處理函式中的 render() 時指定的鍵。
注意:我們沒有轉義計數值(即,我們使用了 !{} 語法),因為計數值是計算出來的。如果資訊是由終端使用者提供的,那麼我們會轉義變數以進行顯示。
它看起來怎麼樣?
此時,我們應該已經建立了顯示索引頁面所需的一切。執行應用程式,然後在瀏覽器中開啟 https://:3000/。如果一切設定正確,您的網站應該看起來像下面的截圖。

注意:您還不能使用側邊欄連結,因為那些頁面的 URL、檢視和模板尚未定義。如果您嘗試,您將收到類似“未實現:圖書列表”的錯誤,具體取決於您單擊的連結。這些字串字面量(將被替換為實際資料)是在“controllers”檔案中存在的不同控制器中指定的。
後續步驟
- 返回 Express 教程第 5 部分:顯示圖書館資料。
- 繼續第五部分下一篇子文章:圖書列表頁。