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-mate或express-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. 模板引擎最佳实践
- 选择适合项目的模板引擎:根据团队熟悉度和项目需求选择合适的模板引擎
- 使用布局和组件:利用模板引擎的布局和组件功能提高代码复用性
- 分离关注点:保持模板专注于展示逻辑,将业务逻辑放在控制器或服务中
- 避免在模板中编写复杂逻辑:复杂逻辑应放在JavaScript代码中
- 使用中间件传递常用数据:使用中间件将常用数据(如用户信息、配置)传递给视图
- 启用视图缓存:在生产环境中启用视图缓存以提高性能
- 使用模板继承:利用模板继承创建一致的页面结构
- 适当注释模板:为复杂的模板部分添加注释以提高可维护性
- 验证用户输入:在渲染前验证和清理用户输入,防止XSS攻击
- 考虑使用前端框架:对于复杂的前端交互,考虑使用React、Vue等前端框架与Express后端分离
9. 练习项目
创建一个具有以下功能的Express应用程序:
- 配置并使用至少两种模板引擎(Pug和EJS)
- 创建布局和可重用组件
- 实现动态内容渲染
- 设置静态文件服务
- 添加全局变量和辅助函数
- 实现局部渲染API
- 在生产环境中启用视图缓存
通过这个练习,你将掌握Express模板引擎的各种高级用法,能够创建动态、美观的Web应用程序界面。