首頁
我們將建立的第一個頁面是網站首頁,可以透過站點 (/) 或目錄 (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 = asyncHandler(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");
const asyncHandler = require("express-async-handler");
exports.index = asyncHandler(async (req, res, next) => {
res.send("NOT IMPLEMENTED: Site Home Page");
});
將上面所有程式碼替換為以下程式碼片段。首先,它匯入(require())所有模型。我們需要這樣做,因為我們將使用它們來獲取文件的計數。該程式碼還要求“express-async-handler”,它提供了一個包裝器來 捕獲路由處理程式函式中丟擲的異常。
const Book = require("../models/book");
const Author = require("../models/author");
const Genre = require("../models/genre");
const BookInstance = require("../models/bookinstance");
const asyncHandler = require("express-async-handler");
exports.index = asyncHandler(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。其他模板語言可能要求您為使用到的所有物件傳入值。
請注意,程式碼非常簡單,因為我們可以假設資料庫查詢成功。如果任何資料庫操作失敗,則丟擲的異常將被 asyncHandler() 捕獲並傳遞給鏈中的 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 部分:顯示庫資料。
- 繼續第 5 部分的下一篇文章:書籍列表頁面。