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

如何使用Vue.js将点赞按钮点击计数存入数据库避免页面刷新重置

解决方案

整体实现逻辑

  • 后端新增数据存储接口,负责将用户的反应计数持久化到数据库
  • 前端页面初始化时从后端拉取当前文章的历史计数赋值
  • 用户点击反应按钮时,前端先更新本地展示,同时上报点击行为到后端同步更新数据库计数

步骤1:后端接口&数据库设计

首先新建文章反应统计表,以MySQL为例,表结构参考:

CREATE TABLE `article_reactions` (
  `id` int NOT NULL AUTO_INCREMENT,
  `article_id` int NOT NULL COMMENT '关联文章ID',
  `reaction_type` varchar(20) NOT NULL COMMENT '反应类型:likes/love/HaHa/Wow/Sad/Angry',
  `count` int NOT NULL DEFAULT '0' COMMENT '对应反应的计数',
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_article_reaction` (`article_id`,`reaction_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

随后开发两个后端接口:

  1. 计数查询接口:GET /api/get-reactions
    请求参数:articleId(当前文章ID)
    返回格式参考:
    {
      "code": 0,
      "data": {
        "likes": 12,
        "love": 5,
        "HaHa": 8,
        "Wow": 3,
        "Sad": 2,
        "Angry": 1
      }
    }
    
  2. 计数更新接口:POST /api/add-reaction
    请求参数:articleId、reactionType(点击的反应类型)
    返回格式参考:
    {
      "code": 0,
      "msg": "更新成功"
    }
    

可选优化:接口增加用户IP/登录用户ID校验,避免同一用户重复刷计数

步骤2:前端Vue代码改造

以下是改造后的完整代码,请求使用原生fetch实现,你也可以替换为自己项目用的请求库,注意替换代码里的articleId为当前页面实际的文章ID变量:

<div class="reaction-wrapper">
        <div class="main">
        <div id="app">
            <!-- Reaction system start -->
            <div class="reaction-container"><!-- container div for reaction system -->
                <span class="reaction-btn"> <!-- Default like button -->
                    <span class="reaction-btn-emo like-btn-default"></span> <!-- Default like button emotion-->
                    <span class="reaction-btn-text">Like</span> <!-- Default like button text,(Like, wow, sad..) default:Like  -->
                    <ul class="emojies-box"> <!-- Reaction buttons container-->
                        <li @click="likeIt" class="emoji emo-like" data-reaction="Like"></li>
                        <li @click="loveIt" class="emoji emo-love" data-reaction="Love"></li>
                        <li @click="HaHaIt" class="emoji emo-haha" data-reaction="HaHa"></li>
                        <li @click="WowIt" class="emoji emo-wow" data-reaction="Wow"></li>
                        <li @click="SadIt" class="emoji emo-sad" data-reaction="Sad"></li>
                        <li @click="AngryIt" class="emoji emo-angry" data-reaction="Angry"></li>
                    </ul>
                </span>
                <div class="like-stat"> <!-- Like statistic container-->
                    <span class="like-emo"> <!-- like emotions container -->
                        <span class="like-btn-like"></span>  <!--given emotions like, wow, sad (default:Like) -->
                    </span>
                     <span class="like-details">Hover over the like button to see your options!</span> 
                </div>
                <div id="likes-counter">
                 <ol>
                  <li>Likes:{{likes}}</li>
                  <li>Love:{{love}}</li>
                  <li>HaHa:{{HaHa}}</li>
                  <li>Wow:{{Wow}}</li>
                  <li>Sad:{{Sad}}</li>
                  <li>Angry:{{Angry}}</li>
                 </ol>
                </div>
            </div>
            <!-- Reaction system end -->
            </div>
        </div>
    </div>

    <script src="https://unpkg.com/vue@2.0.7/dist/vue.js"></script> 

<script>
new Vue({
    el:'#app',
    data:{
        isHidden:true,
        likes:0,
        love:0,
        HaHa:0,
        Wow:0,
        Sad:0,
        Angry:0,
        articleId: 11, // 替换为当前页面实际的文章ID
        isSubmitting: false // 防止重复点击标记
    },
    created() {
        // 页面加载时拉取历史计数
        this.getReactionCounts()
    },
    methods:{
        // 拉取当前文章的所有反应计数
        async getReactionCounts() {
            try {
                const res = await fetch(`/api/get-reactions?articleId=${this.articleId}`)
                const result = await res.json()
                if (result.code === 0) {
                    Object.keys(result.data).forEach(key => {
                        if (this.hasOwnProperty(key)) {
                            this[key] = result.data[key]
                        }
                    })
                }
            } catch (e) {
                console.error('拉取计数失败', e)
            }
        },
        // 上报用户点击的反应类型
        async addReaction(type) {
            if (this.isSubmitting) return
            this.isSubmitting = true
            try {
                await fetch('/api/add-reaction', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({
                        articleId: this.articleId,
                        reactionType: type
                    })
                })
            } catch (e) {
                console.error('上报计数失败', e)
                // 上报失败回滚前端计数
                this[type]--
            } finally {
                this.isSubmitting = false
            }
        },
        showIt:function(){
            this.isHidden=false;
        },
        hideIt:function(){
            this.isHidden=true;
        },
        likeIt:function(){
            this.likes++;
            this.addReaction('likes')
        },
        loveIt:function(){
            this.love++;
            this.addReaction('love')
        },
        HaHaIt:function(){
            this.HaHa++;
            this.addReaction('HaHa')
        },
        WowIt:function(){
            this.Wow++;
            this.addReaction('Wow')
        },
        SadIt:function(){
            this.Sad++;
            this.addReaction('Sad')
        },
        AngryIt:function(){
            this.Angry++;
            this.addReaction('Angry')
        },
    }
});
</script>

如果你的页面需要兼容低版本浏览器不支持async/await语法,可以将请求逻辑替换为Promise.then写法,或引入babel做语法转译


内容的提问来源于stack exchange,提问作者Jason D'Amico

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 22:15:02