跳到主要内容

Express模板引擎与视图渲染

1. 模板引擎概述

模板引擎是一种将模板与数据结合生成HTML页面的工具。在Express中,模板引擎使我们能够动态生成HTML,而不是提供静态HTML文件。

使用模板引擎的主要优势包括:

  • 分离关注点:将展示逻辑与业务逻辑分开
  • 代码复用:可以创建可重用的模板组件
  • 动态内容:根据不同数据生成不同的HTML内容
  • 维护性:更容易维护和更新页面结构

2. 支持的模板引擎

Express支持多种模板引擎,包括但不限于:

  • Pug (前身为Jade)
  • EJS (Embedded JavaScript)
  • Handlebars
  • Mustache
  • Nunjucks
  • Hbs

本文将重点介绍最常用的Pug和EJS模板引擎。

3. 配置模板引擎

3.1 安装模板引擎

首先,需要安装选择的模板引擎:

# 安装Pug
npm install pug --save

# 或安装EJS
npm install ejs --save

3.2 设置模板引擎

在Express应用程序中配置模板引擎:

const express = require('express')
const app = express()

// 设置模板引擎为Pug
app.set('view engine', 'pug')

// 或设置模板引擎为EJS
// app.set('view engine', 'ejs')

// 设置视图目录
app.set('views', './views')

默认情况下,Express会在应用程序根目录下的views文件夹中查找模板文件。如果要使用其他目录,可以通过app.set('views', 'your-view-directory')进行设置。

4. Pug模板引擎

Pug是一种简洁的模板语言,它使用缩进和极简的语法来定义HTML结构。

4.1 基本Pug语法

创建views/index.pug

doctype html
html(lang='zh-CN')
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
h1= title
p 欢迎来到 #{title}!
ul
each user in users
li= user.name

在路由处理程序中渲染Pug模板:

app.get('/', (req, res) => {
res.render('index', {
title: 'Express应用',
users: [
{ name: '张三' },
{ name: '李四' },
{ name: '王五' }
]
})
})

4.2 Pug的主要特性

4.2.1 标签和属性

// 基本标签
div

// 带ID的标签
div#container

// 带类的标签
div.content

// 带属性的标签
img(src='logo.png', alt='Logo', width='200')

// 嵌套标签(使用缩进)
div
p 这是一个段落

4.2.2 插值

// 变量插值
p 欢迎 #{user.name}

// 标签插值(不转义)
p!= '<strong>HTML内容</strong>'

// 表达式插值
p 1 + 1 = #{1 + 1}

4.2.3 条件语句

if user.loggedIn
p 欢迎回来,#{user.name}!
else
p 请登录

// 三元运算符
p #{user.loggedIn ? '已登录' : '未登录'}

4.2.4 循环

ul
each item in items
li= item
else
li 列表为空

// 带索引的循环
ul
each user, index in users
li= index + 1 + '. ' + user.name

4.2.5 混入(Mixins)

Mixins允许你创建可重用的代码块:

// 定义混入
mixin userCard(user)
.card
h3= user.name
p= user.email

// 使用混入
+userCard(user1)
+userCard(user2)

4.2.6 包含和扩展

// 包含其他模板文件
include header.pug

// 继承基础模板
extends layout.pug

// 定义块内容
block content
h1 页面内容

5. EJS模板引擎

EJS (Embedded JavaScript) 是一种简单的模板语言,它允许你在HTML中嵌入JavaScript代码。

5.1 基本EJS语法

创建views/index.ejs

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<h1><%= title %></h1>
<p>欢迎来到 <%= title %>!</p>
<ul>
<% users.forEach(function(user) { %>
<li><%= user.name %></li>
<% }); %>
</ul>
</body>
</html>

在路由处理程序中渲染EJS模板:

app.get('/', (req, res) => {
res.render('index', {
title: 'Express应用',
users: [
{ name: '张三' },
{ name: '李四' },
{ name: '王五' }
]
})
})

5.2 EJS的主要特性

5.2.1 输出内容

<!-- 转义输出 -->
<%= user.name %>

<!-- 非转义输出 -->
<%- '<strong>HTML内容</strong>' %>

<!-- 执行JavaScript但不输出结果 -->
<% console.log('调试信息') %>

5.2.2 条件语句

<% if (user.loggedIn) { %>
<p>欢迎回来,<%= user.name %>!</p>
<% } else { %>
<p>请登录</p>
<% } %>

5.2.3 循环

<ul>
<% for (let i = 0; i < users.length; i++) { %>
<li><%= users[i].name %></li>
<% } %>
</ul>

<!-- 或使用forEach -->
<ul>
<% users.forEach(function(user, index) { %>
<li><%= index + 1 %>. <%= user.name %></li>
<% }); %>
</ul>

5.2.4 包含

<!-- 包含其他模板文件 -->
<%- include('header') %>

<!-- 带数据的包含 -->
<%- include('user/profile', { user: currentUser }) %>

5.2.5 布局

虽然EJS没有内置的布局支持,但可以使用第三方包如ejs-mateexpress-ejs-layouts来实现布局功能:

// 使用express-ejs-layouts
const expressLayouts = require('express-ejs-layouts')

app.use(expressLayouts)
app.set('layout', 'layouts/main')

布局文件views/layouts/main.ejs

<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<%- body %>
</body>
</html>

6. 视图渲染高级技巧

6.1 向所有视图传递数据

使用app.locals可以向所有视图传递全局变量:

app.locals.title = '我的Express应用' // 所有视图都可以访问title变量
app.locals.formatDate = function(date) {
return new Date(date).toLocaleDateString()
} // 所有视图都可以使用formatDate函数

6.2 响应局部渲染

在某些情况下,可能只想渲染页面的一部分而不是整个页面:

app.get('/api/comments', (req, res) => {
// 获取评论数据
const comments = getComments()

// 渲染评论部分视图
res.render('partials/comments', { comments }, (err, html) => {
if (err) return res.status(500).json({ error: err.message })
res.json({ html })
})
})

6.3 视图缓存

在生产环境中启用视图缓存可以提高性能:

// 在生产环境中启用视图缓存
app.set('view cache', process.env.NODE_ENV === 'production')

6.4 自定义模板引擎

如果你想使用Express默认不直接支持的模板引擎,可以通过app.engine方法进行配置:

const nunjucks = require('nunjucks')

// 配置Nunjucks模板引擎
nunjucks.configure('views', {
autoescape: true,
express: app
})

app.set('view engine', 'njk')

7. 静态文件处理

除了渲染动态内容外,Express还可以提供静态文件,如CSS、JavaScript、图片等:

// 提供public目录下的静态文件
app.use(express.static('public'))

// 可以使用虚拟路径前缀
app.use('/static', express.static('public'))

在模板中引用静态文件:

// Pug中引用静态文件
link(rel='stylesheet', href='/stylesheets/style.css')
script(src='/javascripts/main.js')
img(src='/images/logo.png', alt='Logo')

// 如果使用虚拟路径前缀
link(rel='stylesheet', href='/static/stylesheets/style.css')
<!-- EJS中引用静态文件 -->
<link rel='stylesheet' href='/stylesheets/style.css'>
<script src='/javascripts/main.js'></script>
<img src='/images/logo.png' alt='Logo'>

<!-- 如果使用虚拟路径前缀 -->
<link rel='stylesheet' href='/static/stylesheets/style.css'>

8. 模板引擎最佳实践

  1. 选择适合项目的模板引擎:根据团队熟悉度和项目需求选择合适的模板引擎
  2. 使用布局和组件:利用模板引擎的布局和组件功能提高代码复用性
  3. 分离关注点:保持模板专注于展示逻辑,将业务逻辑放在控制器或服务中
  4. 避免在模板中编写复杂逻辑:复杂逻辑应放在JavaScript代码中
  5. 使用中间件传递常用数据:使用中间件将常用数据(如用户信息、配置)传递给视图
  6. 启用视图缓存:在生产环境中启用视图缓存以提高性能
  7. 使用模板继承:利用模板继承创建一致的页面结构
  8. 适当注释模板:为复杂的模板部分添加注释以提高可维护性
  9. 验证用户输入:在渲染前验证和清理用户输入,防止XSS攻击
  10. 考虑使用前端框架:对于复杂的前端交互,考虑使用React、Vue等前端框架与Express后端分离

9. 练习项目

创建一个具有以下功能的Express应用程序:

  1. 配置并使用至少两种模板引擎(Pug和EJS)
  2. 创建布局和可重用组件
  3. 实现动态内容渲染
  4. 设置静态文件服务
  5. 添加全局变量和辅助函数
  6. 实现局部渲染API
  7. 在生产环境中启用视图缓存

通过这个练习,你将掌握Express模板引擎的各种高级用法,能够创建动态、美观的Web应用程序界面。