MEN栈EJS嵌入jQuery报$未定义 点赞计分功能异常排查
问题根因
- 核心错误:将jQuery前端交互代码写在了EJS的
<% %>服务端执行标签内。这部分代码是Express在服务端渲染页面时于Node环境运行的,Node环境没有加载浏览器端jQuery,必然触发$ is not defined报错。jQuery事件逻辑属于浏览器端代码,必须放在普通<script>标签中,在客户端加载执行。 - HTML规范违反:循环生成多个帖子条目时重复使用相同id(
plus/minus/score),id属性要求全局唯一,重复id会导致JS无法正确匹配目标元素。 - 属性书写笔误:点赞按钮写为
is="plus",并非id="plus",即使逻辑位置正确也无法被选中。 - 作用域错误:代码中使用的
relevance、myBoolean都是服务端模板变量,前端点击事件触发时无法访问这些变量。
修正实现
1. 调整模板DOM结构
将重复id替换为class,给元素补充自定义数据属性存储必要信息,修正按钮属性笔误,循环部分对应代码修改如下:
<div class="carousel-item" style="text-align: justify" > <div class="row"> <h2><%= questions[i].title %></h2> <p><%= questions[i].body %></p> </div> <div class="row" style="width: 100%; height: 90px; white-space: nowrap; overflow-x: auto;"> <p style = "display: inline-block; width: 70%; height: 100%;"><strong>Posted by: </strong><%= questions[i].userid.username %> on <%= questions[i].datePosted.toDateString() %> </p> <button class="submit-btn" style = "display: inline-block; width: 30%; height: 50%; border-radius: 5px; background-color:darkcyan" type="submit">View Responses</button> </div> <!-- 投票区域加类名和题目id数据属性 --> <div class="row vote-area" data-qid="<%= questions[i]._id %>" style="width: 100%; height: 90px; white-space: nowrap; overflow-x: auto;"> <!-- 按钮用类选择器,加投票值数据属性 --> <button style = "display: inline-block; width: 25%; height: 50%; border-radius: 5px" class="vote-btn minus" data-val="-1">-</button> <button style = "display: inline-block; width: 25%; height: 50%; border-radius: 5px" class="vote-btn plus" data-val="1">+</button> <!-- 分数数字单独包裹,方便更新 --> <p style = "display: inline-block; width: 50%; height: 100%;" class="score-text"><strong> Score: </strong> <span class="score-num"><%= questions[i].upvotes %></span></p> </div> </div>
2. 写入正确的前端jQuery逻辑
将以下代码放在jQuery引入标签之后、页面所有DOM的末尾,不要套在任何EJS<% %>标签内:
<script> // 等待DOM加载完成后执行 $(document).ready(function() { // 用类选择器给所有投票按钮绑定事件 $('.vote-btn').on('click', function() { // 定位到当前按钮所属的投票区域 const $currentArea = $(this).closest('.vote-area'); // 防重复投票:如果当前区域已经投过票直接返回 if ($currentArea.data('voted')) return; // 获取当前分数和投票值 const $scoreEl = $currentArea.find('.score-num'); let score = parseInt($scoreEl.text()); const voteVal = parseInt($(this).data('val')); // 更新分数 score += voteVal; $scoreEl.text(score); // 标记为已投票 $currentArea.data('voted', true); // 后续需要同步到MongoDB时,在这里写AJAX请求即可 // 示例: // $.post('/api/update-vote', { // questionId: $currentArea.data('qid'), // newScore: score // }) }) }) </script>
后续对接数据库提示
分数更新完成后,给后端写一个接收投票参数的接口,前端在分数更新后发POST请求把题目id、最新分数/投票类型传给后端,后端用Mongoose查找到对应题目更新upvotes字段即可,注意要加用户校验,避免恶意刷票。
内容的提问来源于stack exchange,提问作者Rasputin
相关产品推荐
相关产品推荐

