You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:如何通过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:01:42