EJS教程
EJS教程
简介
EJS (Embedded JavaScript)是一种简单而强大的JavaScript模板引擎,它让你能够在HTML页面中嵌入JavaScript代码。与其他模板引擎相比,EJS的语法非常接近原生JavaScript,学习曲线较低,特别适合已经熟悉JavaScript的开发者。
EJS的主要特点:
- 快速编译和渲染
- 简单的模板标签
- 支持自定义分隔符
- 包含客户端支持
- 支持Express框架
- 没有新的语法需要学习,直接使用JavaScript
安装和设置
在Node.js项目中安装EJS
npm install ejs
基本使用方法
在Node.js应用中:
const ejs = require('ejs');
const fs = require('fs');// 方法1:从字符串渲染
let template = '<h1><%= title %></h1>';
let data = { title: 'EJS模板引擎' };
let html = ejs.render(template, data);console.log(html); // 输出: <h1>EJS模板引擎</h1>// 方法2:从文件渲染
ejs.renderFile('template.ejs', data, (err, html) => {if (err) {console.log(err);} else {console.log(html);}
});
在Express框架中使用
const express = require('express');
const app = express();// 设置EJS为视图引擎
app.set('view engine', 'ejs');
app.set('views', './views'); // 指定模板文件目录// 路由处理
app.get('/', (req, res) => {res.render('index', { title: 'EJS模板引擎' });
});app.listen(3000, () => {console.log('服务器运行在 http://localhost:3000');
});
基本语法
EJS使用标签来嵌入JavaScript代码。基本标签形式如下:
标签 | 描述 |
---|---|
<% %> | 执行JavaScript代码,不输出任何内容 |
<%= %> | 输出转义后的HTML内容 |
<%- %> | 输出原始HTML内容(不转义) |
<%# %> | 注释标签,不执行也不输出 |
<%_ %> | 删除前面的空白字符 |
<% _%> | 删除后面的空白字符 |
<%% | 输出字面的 ‘<%’ |
%%> | 输出字面的 ‘%>’ |
EJS标签
1. 代码执行标签 <% %>
这种标签用于执行JavaScript代码,但不输出任何内容。
<% let name = 'World'; %>
<% if (user) { %><h2>Hello, <%= user.name %></h2>
<% } %>
2. 输出转义内容标签 <%= %>
输出转义后的内容(防止XSS攻击)。
<h1>Hello, <%= name %></h1>
如果name
包含<script>
等HTML标签,会被转义为<script>
。
3. 输出原始内容标签 <%- %>
输出未转义的原始HTML内容。
<%- include('header') %>
<%- htmlContent %>
警告:使用<%-
时要确保内容安全,因为它会按原样输出HTML,可能导致XSS攻击。
4. 注释标签 <%# %>
<%# 这是一个注释,不会被输出 %>
5. 控制空白字符的标签 <%_
和 _%>
<%_ for(let i=0; i<5; i++) { _%><li><%= i %></li>
<%_ } _%>
条件语句
在EJS中使用条件语句和JavaScript中完全一样:
<% if (user) { %><h2>Hello, <%= user.name %></h2>
<% } else { %><h2>请登录</h2>
<% } %><% let status = user.status;switch(status) {case 'admin':
%><span class="admin-badge">管理员</span>
<% break;case 'member':
%><span class="member-badge">会员</span>
<% break;default:
%><span class="guest-badge">访客</span>
<% break;}
%>
循环语句
EJS中的循环也使用标准JavaScript语法:
for循环
<ul>
<% for(let i=0; i<items.length; i++) { %><li><%= items[i].name %></li>
<% } %>
</ul>
forEach循环
<ul>
<% items.forEach(function(item) { %><li><%= item.name %> - <%= item.price %>元</li>
<% }); %>
</ul>
map方法
<ul>
<% users.map(user => { %><li id="user-<%= user.id %>"><%= user.name %></li>
<% }); %>
</ul>
包含其他文件
EJS允许你包含其他模板文件,非常适合创建可复用的组件:
<%- include('header', { title: '我的网站' }) %><main><h1>欢迎访问</h1><p>这是主要内容</p>
</main><%- include('footer', { year: new Date().getFullYear() }) %>
包含文件时可以传递数据对象。如果不传递,则被包含的文件可以访问当前模板的所有变量。
自定义函数和过滤器
在渲染时传递函数
// Node.js代码
app.get('/', (req, res) => {res.render('index', {data: ['apple', 'banana', 'orange'],formatText: function(text) {return text.toUpperCase();}});
});
<!-- EJS模板 -->
<% data.forEach(function(item) { %><li><%= formatText(item) %></li>
<% }); %>
创建EJS过滤器(全局函数)
如果你使用Express,可以创建全局可用的函数:
// 在应用入口文件中设置
app.locals.formatDate = function(date) {const d = new Date(date);return `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()}`;
};
<!-- 在任何模板中使用 -->
<p>发布时间: <%= formatDate(article.publishDate) %></p>
布局模板
EJS本身没有内置布局功能,但可以通过include
和变量组合实现:
方法1:使用include和变量
main-layout.ejs:
<!DOCTYPE html>
<html>
<head><title><%= title %></title><link rel="stylesheet" href="/styles.css">
</head>
<body><%- include('header') %><main><%- body %></main><%- include('footer') %>
</body>
</html>
home.ejs:
<% let body = `<h1>首页</h1><p>欢迎访问我们的网站!</p>
`; %><%- include('main-layout', { title: '首页 - 我的网站',body: body
}) %>
方法2:使用express-ejs-layouts
更简单的方法是使用express-ejs-layouts
中间件:
npm install express-ejs-layouts
const expressLayouts = require('express-ejs-layouts');app.use(expressLayouts);
app.set('layout', 'layouts/main'); // 指定默认布局文件
layouts/main.ejs:
<!DOCTYPE html>
<html>
<head><title><%= title %></title><%- style %>
</head>
<body><%- include('../partials/header') %><main><%- body %></main><%- include('../partials/footer') %><%- script %>
</body>
</html>
然后在页面中,您可以直接编写内容,不需要包含布局:
<h1>首页内容</h1>
<p>这是首页的主要内容</p><%- contentFor('style') %>
<style>h1 {color: blue;}
</style><%- contentFor('script') %>
<script>console.log('页面加载完成');
</script>
最佳实践
1. 保持模板简洁
尽量减少模板中的业务逻辑,将复杂的逻辑放在路由处理器或单独的模块中。
2. 组织模板文件
建议的项目结构:
views/
├── layouts/ <!-- 布局模板 -->
│ └── main.ejs
├── partials/ <!-- 可复用组件 -->
│ ├── header.ejs
│ ├── footer.ejs
│ └── sidebar.ejs
└── pages/ <!-- 页面模板 -->├── home.ejs├── about.ejs└── contact.ejs
3. 使用部分视图
将重复的部分提取为部分视图,提高代码复用性。
4. 注意安全问题
- 使用
<%=
而不是<%-
来避免XSS攻击 - 验证和清理用户输入
- 避免在客户端暴露敏感信息
5. 性能优化
对于需要高性能的应用,考虑启用模板缓存:
// 在生产环境中启用视图缓存
if (process.env.NODE_ENV === 'production') {app.enable('view cache');
}
常见问题解答
Q: EJS和其他模板引擎比如Pug, Handlebars相比有什么优势?
A: EJS的主要优势是学习曲线低,使用纯JavaScript语法,没有引入新的模板语言。这让已经熟悉JavaScript的开发者可以立即上手,而不需要学习新的语法规则。
Q: 如何在EJS中处理表单提交和CSRF保护?
A: 通常使用中间件如csurf
来处理CSRF保护:
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });app.get('/form', csrfProtection, (req, res) => {res.render('form', { csrfToken: req.csrfToken() });
});app.post('/process', csrfProtection, (req, res) => {// 处理表单数据
});
<form action="/process" method="post"><input type="hidden" name="_csrf" value="<%= csrfToken %>"><!-- 其他表单字段 --><button type="submit">提交</button>
</form>
Q: 如何在客户端使用EJS?
A: EJS也可以在浏览器中使用:
<script src="https://cdn.jsdelivr.net/npm/ejs@3.1.6/ejs.min.js"></script>
<script>let template = '<h1><%= title %></h1>';let data = { title: 'EJS在浏览器中' };let html = ejs.render(template, data);document.getElementById('content').innerHTML = html;
</script>
Q: 如何使用EJS自定义分隔符?
A: 可以通过选项设置自定义分隔符:
let template = '[[ title ]]';
let html = ejs.render(template, { title: 'EJS自定义分隔符' }, {delimiter: '[]'
});
Q: 如何处理EJS中的错误?
A: 在Express应用中,可以使用错误处理中间件:
app.get('/', (req, res, next) => {try {res.render('index', { data: undefined.property }); // 会产生错误} catch (err) {next(err);}
});// 错误处理中间件
app.use((err, req, res, next) => {console.error(err);res.status(500).render('error', { error: err });
});
这个教程涵盖了EJS的基本概念和高级用法。随着您的深入学习,您会发现EJS是一个既简单又强大的模板引擎,特别适合熟悉JavaScript的开发者使用。