如何使用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;
随后开发两个后端接口:
- 计数查询接口:GET /api/get-reactions
请求参数:articleId(当前文章ID)
返回格式参考:{ "code": 0, "data": { "likes": 12, "love": 5, "HaHa": 8, "Wow": 3, "Sad": 2, "Angry": 1 } } - 计数更新接口: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
相关产品推荐
相关产品推荐

