求助:如何通过Ajax实现点赞功能并适配Node.js路由?
没问题,我帮你一步步实现这个Ajax点赞功能,结合Node.js和Handlebars,分前端和后端两部分来做:
实现基于Ajax的点赞功能(Node.js + Handlebars)
第一步:前端Handlebars模板调整
首先在你的Handlebars帖子模板里,给点赞按钮和点赞数元素加上唯一标识,方便后续JS定位操作:
<!-- 帖子模板片段 --> <div class="post-card" data-post-id="{{post.id}}"> <div class="like-area"> <span class="like-number">{{post.likes}}</span> 次点赞 <button class="like-button">点赞</button> </div> </div>
这里用data-post-id存储帖子ID,like-number类标记点赞数显示区域,like-button作为按钮的统一选择器。
第二步:前端Ajax请求实现
用现代的fetch API写Ajax逻辑(也可以用jQuery的$.ajax,原生fetch更轻量化),在页面的<script>标签或单独JS文件中添加:
// 等待页面DOM加载完成再绑定事件 document.addEventListener('DOMContentLoaded', function() { // 给所有点赞按钮绑定点击事件 document.querySelectorAll('.like-button').forEach(btn => { btn.addEventListener('click', async function() { const postCard = this.closest('.post-card'); const postId = postCard.dataset.postId; const likeNumEl = postCard.querySelector('.like-number'); // 先禁用按钮防止重复点击,提升体验 this.disabled = true; this.textContent = '点赞中...'; try { // 发送POST请求到后端接口 const response = await fetch(`/api/posts/${postId}/like`, { method: 'POST', headers: { 'Content-Type': 'application/json', // 如果你的应用有CSRF保护,记得加上CSRF Token: // 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content } }); if (!response.ok) { throw new Error('请求失败,请稍后重试'); } // 解析后端返回的JSON结果 const data = await response.json(); // 更新页面上的点赞数 likeNumEl.textContent = data.newLikeCount; // 更新按钮状态为已点赞 this.textContent = '已点赞'; } catch (err) { console.error('点赞出错:', err); alert('点赞失败,请重试'); // 恢复按钮可点击状态 this.disabled = false; this.textContent = '点赞'; } }); }); });
第三步:后端Node.js路由与数据库操作
假设你用Express框架,分两种常见数据库场景给出实现示例:
1. 基础配置:注册路由与解析请求体
先确保你的Express app已经配置了解析JSON请求体,否则拿不到后端请求数据:
const express = require('express'); const app = express(); // 必须配置这个,才能解析JSON格式的请求体 app.use(express.json()); // 引入点赞路由(假设路由写在routes/like.js) app.use('/api/posts', require('./routes/like'));
2. 场景一:MongoDB + Mongoose
假设你有一个Post模型:
// models/Post.js const mongoose = require('mongoose'); const postSchema = new mongoose.Schema({ // 你的其他字段(比如标题、内容) likes: { type: Number, default: 0 }, // 可选:添加likedBy字段,存储已点赞用户ID,防止重复点赞 likedBy: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' }] }); module.exports = mongoose.model('Post', postSchema);
然后在routes/like.js里写路由逻辑:
const express = require('express'); const router = express.Router(); const Post = require('../models/Post'); // 处理点赞请求:POST /api/posts/:postId/like router.post('/:postId/like', async (req, res) => { try { const postId = req.params.postId; // 【可选】如果要防止重复点赞,先获取当前登录用户ID(需结合passport/session) // const userId = req.user._id; // 方式一:直接递增点赞数(不防重复) const updatedPost = await Post.findByIdAndUpdate( postId, { $inc: { likes: 1 } }, // MongoDB的递增操作符 { new: true } // 返回更新后的文档 ); // 方式二:防止重复点赞(需likedBy字段) // const post = await Post.findById(postId); // if (!post) return res.status(404).json({ error: '帖子不存在' }); // if (post.likedBy.includes(userId)) { // return res.status(400).json({ error: '你已经点赞过啦' }); // } // post.likes += 1; // post.likedBy.push(userId); // await post.save(); if (!updatedPost) { return res.status(404).json({ error: '帖子不存在' }); } // 返回最新点赞数给前端 res.json({ newLikeCount: updatedPost.likes }); } catch (err) { console.error('处理点赞出错:', err); res.status(500).json({ error: '服务器内部错误' }); } }); module.exports = router;
3. 场景二:MySQL + mysql2
假设你的posts表有id和likes字段,路由逻辑如下:
const express = require('express'); const router = express.Router(); const mysql = require('mysql2/promise'); // 创建数据库连接池 const pool = mysql.createPool({ host: 'localhost', user: '你的数据库用户名', password: '你的数据库密码', database: '你的数据库名' }); router.post('/:postId/like', async (req, res) => { try { const postId = req.params.postId; // 递增点赞数 const [updateResult] = await pool.execute( 'UPDATE posts SET likes = likes + 1 WHERE id = ?', [postId] ); if (updateResult.affectedRows === 0) { return res.status(404).json({ error: '帖子不存在' }); } // 查询最新点赞数 const [rows] = await pool.execute( 'SELECT likes FROM posts WHERE id = ?', [postId] ); res.json({ newLikeCount: rows[0].likes }); } catch (err) { console.error('处理点赞出错:', err); res.status(500).json({ error: '服务器内部错误' }); } }); module.exports = router;
第四步:测试功能
启动你的Node.js服务,打开页面点击点赞按钮,应该能看到:
- 按钮暂时变成“点赞中...”,随后变为“已点赞”
- 页面上的点赞数自动+1
- 数据库里的
likes字段同步递增
如果遇到问题,可以打开浏览器控制台看错误信息,或者后端控制台查日志定位问题。
内容的提问来源于stack exchange,提问作者Alpit Anand
相关产品推荐
相关产品推荐

