EJS模板 #
一、EJS简介 #
1.1 什么是EJS? #
EJS(Embedded JavaScript)是一种简单的模板语言,让你可以使用纯JavaScript语法生成HTML。
1.2 特点 #
- 语法简单,类似HTML
- 支持JavaScript所有语法
- 支持模板包含和继承
- 性能良好
1.3 安装 #
bash
npm install ejs
二、基本配置 #
2.1 设置视图引擎 #
javascript
const express = require('express');
const app = express();
app.set('view engine', 'ejs');
app.set('views', './views');
2.2 自定义文件扩展名 #
javascript
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
三、EJS语法 #
3.1 输出标签 #
| 标签 | 说明 | 示例 |
|---|---|---|
| <%= %> | 输出(转义) | <%= name %> |
| <%- %> | 输出(不转义) | <%- html %> |
| <% %> | 执行代码 | <% if (user) { %> |
| <%# %> | 注释 | <%# 注释内容 %> |
| -%> | 去除换行 | <% code -%> |
3.2 输出变量 #
html
<p><%= name %></p>
<p><%= user.name %></p>
<p><%= users[0].name %></p>
3.3 条件语句 #
html
<% if (user) { %>
<p>欢迎, <%= user.name %></p>
<% } else { %>
<p>请登录</p>
<% } %>
3.4 循环语句 #
html
<ul>
<% items.forEach(item => { %>
<li><%= item.name %></li>
<% }); %>
</ul>
html
<% for (let i = 0; i < items.length; i++) { %>
<p><%= i + 1 %>. <%= items[i] %></p>
<% } %>
3.5 switch语句 #
html
<% switch (status) { %>
<% case 'active': %>
<span class="badge-success">激活</span>
<% break %>
<% case 'inactive': %>
<span class="badge-warning">未激活</span>
<% break %>
<% default: %>
<span class="badge-secondary">未知</span>
<% } %>
四、包含文件 #
4.1 include语法 #
html
<%- include('header') %>
<%- include('partials/nav', { user: user }) %>
<main>内容</main>
<%- include('footer') %>
4.2 文件结构 #
text
views/
├── partials/
│ ├── header.ejs
│ ├── nav.ejs
│ └── footer.ejs
├── index.ejs
└── about.ejs
4.3 header.ejs #
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title><%= title %></title>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
4.4 footer.ejs #
html
<script src="/js/main.js"></script>
</body>
</html>
4.5 使用示例 #
html
<%- include('partials/header', { title: '首页' }) %>
<%- include('partials/nav') %>
<div class="container">
<h1><%= message %></h1>
</div>
<%- include('partials/footer') %>
五、布局模板 #
5.1 安装express-ejs-layouts #
bash
npm install express-ejs-layouts
5.2 配置 #
javascript
const expressLayouts = require('express-ejs-layouts');
app.use(expressLayouts);
app.set('layout', 'layouts/main');
5.3 布局文件 #
views/layouts/main.ejs:
html
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<%- include('partials/head') %>
</head>
<body>
<%- include('partials/header') %>
<main>
<%- body %>
</main>
<%- include('partials/footer') %>
</body>
</html>
5.4 页面模板 #
views/index.ejs:
html
<h1>首页</h1>
<p>欢迎来到我的网站</p>
5.5 路由 #
javascript
app.get('/', (req, res) => {
res.render('index', { title: '首页' });
});
六、过滤器 #
6.1 自定义过滤器 #
javascript
const ejs = require('ejs');
ejs.filters.trim = (str) => str.trim();
ejs.filters.upper = (str) => str.toUpperCase();
ejs.filters.lower = (str) => str.toLowerCase();
ejs.filters.date = (date) => new Date(date).toLocaleDateString();
6.2 使用过滤器 #
html
<p><%=: name | trim | upper %></p>
<p><%=: createdAt | date %></p>
七、辅助函数 #
7.1 注册辅助函数 #
javascript
app.locals.formatDate = (date) => {
return new Date(date).toLocaleDateString('zh-CN');
};
app.locals.truncate = (str, length) => {
if (str.length > length) {
return str.substring(0, length) + '...';
}
return str;
};
app.locals.eq = (a, b) => a === b;
7.2 使用辅助函数 #
html
<p><%= formatDate(user.createdAt) %></p>
<p><%= truncate(post.content, 100) %></p>
<% if (eq(status, 'active')) { %>
<span>激活</span>
<% } %>
八、完整示例 #
8.1 项目结构 #
text
views/
├── layouts/
│ └── main.ejs
├── partials/
│ ├── header.ejs
│ ├── footer.ejs
│ └── nav.ejs
├── index.ejs
├── users/
│ ├── index.ejs
│ └── show.ejs
└── posts/
├── index.ejs
└── show.ejs
8.2 布局文件 #
views/layouts/main.ejs:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= title %> - <%= siteName %></title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<%- include('../partials/header') %>
<div class="container mt-4">
<% if (messages.error) { %>
<div class="alert alert-danger"><%= messages.error %></div>
<% } %>
<% if (messages.success) { %>
<div class="alert alert-success"><%= messages.success %></div>
<% } %>
<%- body %>
</div>
<%- include('../partials/footer') %>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
8.3 用户列表页面 #
views/users/index.ejs:
html
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>用户列表</h2>
<a href="/users/new" class="btn btn-primary">添加用户</a>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>邮箱</th>
<th>角色</th>
<th>创建时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<% users.forEach(user => { %>
<tr>
<td><%= user.id %></td>
<td><%= user.name %></td>
<td><%= user.email %></td>
<td>
<span class="badge <%= user.role === 'admin' ? 'bg-danger' : 'bg-primary' %>">
<%= user.role %>
</span>
</td>
<td><%= formatDate(user.createdAt) %></td>
<td>
<a href="/users/<%= user.id %>" class="btn btn-sm btn-info">查看</a>
<a href="/users/<%= user.id %>/edit" class="btn btn-sm btn-warning">编辑</a>
<form action="/users/<%= user.id %>?_method=DELETE" method="POST" style="display: inline;">
<button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('确定删除?')">删除</button>
</form>
</td>
</tr>
<% }); %>
</tbody>
</table>
<% if (totalPages > 1) { %>
<nav>
<ul class="pagination justify-content-center">
<% if (currentPage > 1) { %>
<li class="page-item">
<a class="page-link" href="/users?page=<%= currentPage - 1 %>">上一页</a>
</li>
<% } %>
<% for (let i = 1; i <= totalPages; i++) { %>
<li class="page-item <%= currentPage === i ? 'active' : '' %>">
<a class="page-link" href="/users?page=<%= i %>"><%= i %></a>
</li>
<% } %>
<% if (currentPage < totalPages) { %>
<li class="page-item">
<a class="page-link" href="/users?page=<%= currentPage + 1 %>">下一页</a>
</li>
<% } %>
</ul>
</nav>
<% } %>
8.4 路由 #
javascript
app.get('/users', async (req, res) => {
const page = parseInt(req.query.page) || 1;
const limit = 10;
const users = await User.find()
.skip((page - 1) * limit)
.limit(limit);
const total = await User.countDocuments();
const totalPages = Math.ceil(total / limit);
res.render('users/index', {
title: '用户列表',
users,
currentPage: page,
totalPages
});
});
九、总结 #
EJS要点:
| 语法 | 说明 |
|---|---|
| <%= %> | 转义输出 |
| <%- %> | 不转义输出 |
| <% %> | 执行代码 |
| include | 包含文件 |
| app.locals | 全局变量 |
下一步,让我们学习Pug模板!
最后更新:2026-03-28