ExpressJS - 模板引擎
Express.js - 现代模板引擎
Section titled “Express.js - 现代模板引擎”在构建 Web 应用程序时,你经常需要生成动态 HTML 页面。与其在服务器代码中手动构建 HTML 字符串(这容易出错且难以维护),不如使用模板引擎。模板引擎允许你编写带有特殊语法的静态模板文件,以便在将页面发送到客户端之前在服务器上动态插入数据。
Pug(以前称为 Jade)是一个流行且功能强大的 Node.js 和浏览器模板引擎。它具有简洁、基于缩进的语法,简化了 HTML 编写,并支持包含(includes)、继承(inheritance)和插值(interpolation)等功能。虽然我们将重点关注 Pug,但其他流行的引擎如 EJS(使用带有 <% %> 标签的纯 HTML)和 Handlebars(使用 {{ }} 标签)也是不错的选择。
在 Express 中设置 Pug
Section titled “在 Express 中设置 Pug”首先,你需要将 Pug 添加为项目依赖项。在项目根目录中打开终端并运行:
npm install pug接下来,配置 Express 使用 Pug 作为其视图引擎(view engine)。你不需要显式地 require('pug');当你设置引擎时,Express 会在内部处理它。将这两行添加到你的主应用程序文件(例如 index.js)中:
// 将视图引擎设置为 Pugapp.set('view engine', 'pug');
// 指定模板文件所在的目录app.set('views', './views');按照惯例,Express 会在项目根目录中的 views 目录中查找模板。让我们创建这个目录并在其中创建一个简单的 Pug 文件。
你的第一个 Pug 模板
Section titled “你的第一个 Pug 模板”创建一个名为 views 的新目录。在其中,创建一个名为 first_view.pug 的文件,内容如下:
doctype htmlhtml(lang="en") head meta(charset="UTF-8") meta(name="viewport", content="width=device-width, initial-scale=1.0") title Hello Pug body p.greetings#people Hello World!关于现代实践的注意事项:
<html>标签上的lang="en"属性有利于可访问性(accessibility)和 SEO。viewportmeta 标签对于移动设备上的响应式设计至关重要。
现在,在 index.js 中创建一个路由,使用 res.render() 渲染此模板:
app.get('/first-template', (req, res) => { // Express 会在 'views' 目录中查找 'first_view.pug' res.render('first_view');});你的完整 index.js 现在应该看起来像这样:
index.js
Section titled “index.js”import express from 'express';
const app = express();const PORT = process.env.PORT || 3000;
// 配置视图引擎app.set('view engine', 'pug');app.set('views', './views');
// 渲染模板的路由app.get('/first-template', (req, res) => { res.render('first_view');});
app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`);});运行你的服务器(如果你已经使用 nodemon 设置了脚本,则运行 npm run dev),然后导航到 http://localhost:3000/first-template。你将看到一个显示“Hello World!”文本的页面。Pug 会将你简洁的 .pug 文件编译成标准的 HTML:
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Hello Pug</title> </head> <body> <p class="greetings" id="people">Hello World!</p> </body></html>Pug 核心功能
Section titled “Pug 核心功能”向模板传递数据
Section titled “向模板传递数据”模板的真正强大之处在于能够从路由处理程序向模板传递动态数据。res.render() 的第二个参数是一个包含你要传递的数据的对象。
让我们创建一个新路由和相应的模板:
路由处理程序 (在 index.js 中)
Section titled “路由处理程序 (在 index.js 中)”app.get('/profile/:username', (req, res) => { const user = { name: req.params.username, isLoggedIn: true, lastLogin: new Date(), interests: ['Web Development', 'Node.js', 'Express'] };
res.render('profile', { title: `${user.name}'s Profile`, user: user });});模板 (views/profile.pug)
Section titled “模板 (views/profile.pug)”doctype htmlhtml(lang="en") head title= title body //- 这是一个 Pug 注释。它不会出现在 HTML 输出中。
// 使用 '=' 输出转义的 HTML。这可以防止 XSS 攻击。 h1 Welcome, #{user.name}!
// 使用 'if/else' 进行条件判断 if user.isLoggedIn p Your last login was on #{user.lastLogin.toLocaleDateString()}. else p Please log in to see your details.
// 使用 'each' 进行循环 if user.interests.length h2 Your Interests: ul each interest in user.interests li= interest else p You have no listed interests.现在,如果你访问 http://localhost:3000/profile/Alice,Pug 将使用 user 对象生成一个动态 HTML 页面。这种将变量直接嵌入文本的技术称为插值(#{variableName})。
条件判断和循环
Section titled “条件判断和循环”如上所示,你可以在 Pug 模板中直接使用类似 JavaScript 的控制流:
- 条件判断:
if、else if、else和unless(即if !(...))。 - 迭代:使用
each val in array或each val, index in array来遍历数组。你也可以使用while循环。
包含和布局 (DRY 原则)
Section titled “包含和布局 (DRY 原则)”为了避免在每个页面上重复编写像页眉和页脚这样的代码(遵循 Don’t Repeat Yourself 即不要重复你自己原则),Pug 提供了 include 和模板继承(extends 和 block)。
使用 include:创建可重用组件。
views/partials/header.pug
Section titled “views/partials/header.pug”header nav a(href='/') Home a(href='/about') Aboutviews/partials/footer.pug
Section titled “views/partials/footer.pug”footer p © #{new Date().getFullYear()} My Awesome Appviews/home.pug
Section titled “views/home.pug”doctype htmlhtml(lang="en") head title Home Page body include partials/header.pug
main h1 Welcome to the Home Page!
include partials/footer.pug使用布局:一种更强大的方法是定义一个基础布局并对其进行扩展。
views/layout.pug (基础模板)
Section titled “views/layout.pug (基础模板)”doctype htmlhtml(lang="en") head title= title || 'My App' link(rel='stylesheet', href='/css/style.css') body include partials/header.pug
main.container block content //- 子模板的内容将插入到这里
include partials/footer.pugviews/about.pug (子模板)
Section titled “views/about.pug (子模板)”extends layout.pug
block content h1 About Us p This is the about page for our awesome application.何时使用服务器端渲染 (SSR)
Section titled “何时使用服务器端渲染 (SSR)”使用像 Pug 这样的模板引擎是一种**服务器端渲染(SSR)**形式。这种方法非常适用于:
- 内容密集型网站:博客、电子商务网站和新闻门户网站受益于快速的初始加载时间和强大的 SEO。
- 搜索引擎优化 (SEO):搜索引擎可以轻松抓取和索引预渲染的 HTML 内容。
- 简洁性:对于许多应用程序而言,SSR 比完整的客户端框架更易于设置和管理。
另一种方法是使用 Express 构建一个 REST API,将 JSON 数据发送到使用 React、Vue 或 Angular 等框架构建的独立单页应用程序 (SPA)。SPA 然后在用户的浏览器中处理所有渲染。这对于高度交互的、类似应用程序的体验(例如仪表板、社交媒体动态)来说是一个很好的选择。