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

Vue.js页面刷新/路由跳转时点赞数据丢失问题解决方案

问题原因

你遇到的点赞数刷新/跳页丢失问题,不需要用Vuex或者localStorage就能解决,本质是三个逻辑疏漏:

  1. CardArticle组件内部的likes变量初始值写死为0,组件初始化时没有读取父组件传入的文章对象自带的点赞数,每次组件重新创建(刷新、路由跳转返回)都会重置为0
  2. 子组件点赞成功后只更新了内部的likes值,没有同步通知父组件更新文章列表的对应数据,容易出现同页数据不一致
  3. 需要先确认后端接口是否真的做了数据库持久化:如果后端点赞接口只是临时返回数值、没把点赞数写入数据库,前端怎么写刷新都会丢——本来这类用户交互数据就应该存在服务端数据库,不需要前端做本地存储。

修复步骤

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 22:09:21