Vue.js页面刷新/路由跳转时点赞数据丢失问题解决方案
问题原因
你遇到的点赞数刷新/跳页丢失问题,不需要用Vuex或者localStorage就能解决,本质是三个逻辑疏漏:
CardArticle组件内部的likes变量初始值写死为0,组件初始化时没有读取父组件传入的文章对象自带的点赞数,每次组件重新创建(刷新、路由跳转返回)都会重置为0- 子组件点赞成功后只更新了内部的
likes值,没有同步通知父组件更新文章列表的对应数据,容易出现同页数据不一致 - 需要先确认后端接口是否真的做了数据库持久化:如果后端点赞接口只是临时返回数值、没把点赞数写入数据库,前端怎么写刷新都会丢——本来这类用户交互数据就应该存在服务端数据库,不需要前端做本地存储。
修复步骤
1. 先确认后端逻辑符合要求
先保证后端两个接口逻辑正确,这是数据不丢的核心:
- 调用
POST /api/articles/:id/like时,服务端会把对应文章的点赞数更新写入数据库,同时记录当前用户的点赞状态(防止重复点赞) - 调用
GET /api/articles拉取文章列表时,每篇返回的文章对象里自带最新的likes字段值
2. 修复CardArticle组件逻辑
你现在的组件只有点击点赞时才会给likes赋值,挂载阶段完全没用到传入的post里的点赞数据,这是显示0的直接原因。修改组件代码:
<template> <div id="card"> <div> <a class="cardLink"> <img class="card-img" v-if="post.imageUrl !== undefined" :src="post.imageUrl" /> <h2 class="cardTitle"> {{ post.title }}</h2> <p class="cardDescription"> {{ post.description }}</p> </a> </div> <div class="buttonIcon"> <div> <button type="button" class="buttonDelete" id="buttonDelete" @click="deletePost" v-if="this.post.userId === this.user.userId || this.user.isAdmin === true">Supprimer</button> <button type="button" class="buttonEdit" id="buttonEdit" @click="modifyPost" v-if="this.post.userId === this.user.userId || this.user.isAdmin === true"> Editer </button> </div> <div class="divIconLike"> <div class="iconLike"> <a @click="sendLike"> <i class="fa-regular fa-thumbs-up"></i> </a> </div> <div class="countLike"> <p> {{ likes }} </p> </div> </div> </div> </div> </template> <script> import axios from "axios"; import router from "../router/index.js"; export default { name: 'CardArticle', data () { return { likes: 0 } }, props: { post: { type: Object, required: true } }, computed: { user() { return this.$store.getters.user; } }, mounted() { // 组件挂载时直接取传入文章的点赞数作为初始值 this.likes = this.post.likes || 0 }, watch: { // 监听父组件传入的post变化,同步更新点赞数 post: { handler(newVal) { this.likes = newVal.likes || 0 }, deep: true } }, methods: { sendLike() { axios.post(`http://localhost:3000/api/articles/${this.post._id}/like`, { userId: this.user.userId }, { headers: { Authorization: `Bearer ${this.user.token}` } }) .then(response => { this.likes = response.data.article.likes // 通知父组件更新对应文章的点赞数,保证全局数据一致 this.$emit('update-like', { postId: this.post._id, likes: response.data.article.likes }) }) .catch(error => console.log(error)) }, deletePost() { // 保留你原有的删除逻辑 }, modifyPost() { // 保留你原有的编辑逻辑 } } } </script>
3. 修复父组件home.vue逻辑
父组件需要监听子组件的点赞更新事件,同步修改本地维护的文章列表数据,顺便修复你原来写的key错误(MongoDB默认主键是_id,你原来写的post.id会导致key无效):
<template> <div class="home" v-if="this.user.token !== null"> <CardArticle v-for="post in allPosts" v-bind:key="post._id" :post="post" @update-like="handleUpdateLike" /> </div> </template> <script> import CardArticle from "../components/CardArticle.vue" import axios from "axios"; export default { name: 'HomeArticle', data () { return { post: { title: "", description: "", imageUrl: "" }, allPosts: [], } }, computed: { user() { return this.$store.getters.user; } }, components: { CardArticle, }, methods: { // 处理子组件上报的点赞更新 handleUpdateLike({postId, likes}) { const target = this.allPosts.find(item => item._id === postId) if (target) target.likes = likes } }, mounted() { axios.get("http://localhost:3000/api/articles", { headers: { Authorization: "Bearer " + this.user.token } }) .then(response => { this.allPosts = response.data; }) .catch(error => { return error; }) } } </script>
验证方式
改完代码后如果还有问题,直接打开浏览器F12看网络请求:
- 如果
GET /api/articles接口返回的文章列表里likes字段是0,说明后端没把点赞数写入数据库,去调整后端逻辑即可 - 如果接口返回的
likes是正确的数值但页面显示0,检查字段名是否匹配,比如后端如果返回的点赞字段叫likeCount,对应修改前端取值的字段名就行
这种方案完全不需要引入额外的状态管理工具或者本地存储,数据存在后端数据库是最可靠的持久化方式,换浏览器、清缓存都不会丢数据。
内容的提问来源于stack exchange,提问作者Benoit
相关产品推荐
相关产品推荐

