如何在页面加载后/事件触发时调用Express变量,避免提前执行?
办公室地图弹窗显示工位用户信息解决方案
问题核心
当前实现是通过页面跳转获取工位用户信息,但需求是在原页面弹窗展示。之前尝试在EJS中嵌入局部模板时报错,原因是EJS是服务器端渲染模板,页面加载时会立即解析所有EJS标签,而初始加载首页时没有传递user参数,导致users.ejs中user变量未定义。
可行方案
方案1:前端异步请求(Fetch)+ 动态渲染弹窗
适合工位数量较多的场景,点击工位时通过API请求获取数据,再动态填充弹窗内容,无需页面跳转。
1. 修改app.js,新增API接口返回JSON数据
保留原有页面路由(若需保留跳转功能),新增专门返回用户数据的API:
// 新增API接口,返回指定工位的用户JSON app.get("/api/user/:place", async (req,res) => { try { const place = req.params.place; const user = await getUser(place); res.json(user); } catch (err) { res.status(500).json({error: '获取用户信息失败'}); } }); // 首页路由,仅渲染index.ejs,无需传递user参数 app.get("/", (req,res) => { res.render('index.ejs'); });
2. 修改index.ejs,添加弹窗容器与点击事件
移除area标签的href,改用点击事件触发请求,动态渲染弹窗:
<!-- 隐藏的弹窗容器 --> <div id="userPopup" style="display:none; position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); padding:20px; background:#fff; border:1px solid #ddd; border-radius:8px; z-index:1000;"> <div class="popup_title"> <h2>姓名: <span id="userName"></span></h2> </div> <div class="popup_text"> <p>工位: <span id="userPlace"></span></p> <!-- 可添加更多用户信息字段,如邮箱、部门等 --> </div> <button style="margin-top:15px; padding:8px 16px;" onclick="closePopup()">关闭</button> </div> <!-- 修改area标签,绑定点击事件 --> <area onclick="showUserInfo('6А1')" coords="1048,515,1001,560" shape="rect"> <script> function showUserInfo(place) { // 发送异步请求获取用户数据 fetch(`/api/user/${place}`) .then(res => res.json()) .then(user => { // 填充弹窗内容 document.getElementById('userName').textContent = user.name; document.getElementById('userPlace').textContent = user.place; // 显示弹窗 document.getElementById('userPopup').style.display = 'block'; }) .catch(err => { console.error('请求错误:', err); alert('获取用户信息失败'); }); } function closePopup() { document.getElementById('userPopup').style.display = 'none'; } </script>
方案2:服务器预加载所有工位数据(适合小数据量场景)
如果办公室工位数量较少,可在首页加载时一次性获取所有用户数据,点击工位时直接从本地数据中匹配,无需每次请求服务器。
1. 修改database.js,新增获取所有用户的函数
export async function getAllUsers() { const [rows] = await pool.query(`SELECT * FROM users`); return rows; }
2. 修改app.js,首页传递所有用户数据
app.get("/", async (req,res) => { try { const allUsers = await getAllUsers(); // 将数据转为JSON字符串传递给前端 res.render('index.ejs', { allUsers: JSON.stringify(allUsers) }); } catch (err) { res.status(500).send('页面加载失败'); } });
3. 修改index.ejs,本地匹配数据渲染弹窗
<div id="userPopup" style="display:none; position:fixed; top:50%; left:50%; transform:translate(-50%,-50%); padding:20px; background:#fff; border:1px solid #ddd; border-radius:8px; z-index:1000;"> <div class="popup_title"> <h2>姓名: <span id="userName"></span></h2> </div> <div class="popup_text"> <p>工位: <span id="userPlace"></span></p> </div> <button style="margin-top:15px; padding:8px 16px;" onclick="closePopup()">关闭</button> </div> <area onclick="showUserInfo('6А1')" coords="1048,515,1001,560" shape="rect"> <script> // 将服务器传递的JSON转为JS对象 const allUsers = JSON.parse('<%= allUsers %>'); function showUserInfo(place) { // 匹配对应工位的用户 const user = allUsers.find(u => u.place === place); if (user) { document.getElementById('userName').textContent = user.name; document.getElementById('userPlace').textContent = user.place; document.getElementById('userPopup').style.display = 'block'; } else { alert('该工位暂无用户信息'); } } function closePopup() { document.getElementById('userPopup').style.display = 'none'; } </script>
关键说明
- 之前的错误根源:EJS模板在服务器端解析完成后才会发送到前端,前端JS函数中无法再执行EJS标签,因此不能把
include('users.ejs')放在前端点击函数里。 - 方案选择:工位数量多选方案1(减少初始加载压力),数量少选方案2(提升交互速度)。
内容的提问来源于stack exchange,提问作者ElCrapachino
相关产品推荐
相关产品推荐

