使用按钮事件加载EJS局部视图失败,如何修复?
问题:点击按钮加载EJS局部视图失败,报DOMException错误
错误原因
- EJS模板语法仅在服务端解析:客户端原生JS中的
<%-require('../views/partials/hi.ejs')%>是服务端EJS的模板语法,浏览器无法识别这段代码,会直接将其作为字符串传入createElement方法。由于该字符串包含<、%等非法标签字符,不符合HTML标签名规范,因此触发DOMException错误。 - 客户端无权访问服务端视图目录:你的Express仅将
public目录设置为静态资源目录,views目录对客户端不可见,即便能解析require语法,客户端也无法获取到服务端的视图文件。
修复方案
方案1:通过AJAX请求服务端渲染后的局部视图
适合需要动态数据的局部视图,每次请求可携带参数让服务端渲染不同内容。
- 服务端新增接口:在Node.js代码中添加接口返回渲染好的
hi.ejs局部视图:
const express = require('express') const app = express() app.set('view engine','ejs') app.use(express.static('public')) app.get('/',(req,res)=>{ res.render('layout') }) // 新增接口:返回渲染后的hi局部视图(可传入动态数据) app.get('/partials/hi', (req, res) => { // 如需传动态数据:res.render('partials/hi', { username: 'test' }) res.render('partials/hi') }) app.listen(5000,()=>{ console.log('server listening') })
- 修改客户端JS:用
fetch请求接口,获取HTML后插入页面:
const button = document.getElementById('button') button.addEventListener('click', async () => { try { const response = await fetch('/partials/hi') const html = await response.text() // 创建临时容器解析HTML,避免直接插入字符串的潜在问题 const tempContainer = document.createElement('div') tempContainer.innerHTML = html // 将解析后的DOM元素添加到页面 document.body.appendChild(tempContainer.firstElementChild) } catch (error) { console.error('加载局部视图失败:', error) } })
方案2:提前将局部视图作为模板嵌入页面
适合静态局部视图,无需每次请求服务端,性能更优。
- 在服务端模板中嵌入局部视图:在
layout.ejs的body中添加隐藏的模板容器,用EJS提前渲染hi.ejs内容:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>hi</title> <link rel="stylesheet" href="main.css"> </head> <body> <button id="button">Im a button</button> <!-- 隐藏的局部视图模板 --> <script type="text/template" id="hi-template"> <%- include('./partials/hi.ejs') %> </script> <script src="main.js" type="module"></script> </body> </html>
- 修改客户端JS:点击按钮时读取模板内容并插入页面:
const button = document.getElementById('button') // 提前获取模板内容 const hiTemplateContent = document.getElementById('hi-template').innerHTML button.addEventListener('click', () => { const tempContainer = document.createElement('div') tempContainer.innerHTML = hiTemplateContent document.body.appendChild(tempContainer.firstElementChild) })
内容的提问来源于stack exchange,提问作者user19624774
相关产品推荐
相关产品推荐

