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

Vue3页面通过router-link跳转后内容不加载,需刷新才显示

解决Vue3路由跳转后页面冻结、v-for内容不渲染的问题

核心问题分析

从你的代码和描述来看,页面冻结、v-for内容无法正常渲染的主要原因集中在以下几点:

  1. Firebase实时监听重复触发,导致keyAreas数组无限累加,页面渲染压力过大
  2. 使用数组索引作为v-for的key,引发Vue DOM复用错误,导致渲染异常
  3. 未处理user异步加载的情况,初始时user.value为null,导致后续查询逻辑异常
  4. 模板中用到的updateChartData方法未定义,引发报错中断渲染流程

分步解决方案

1. 修复Firebase监听逻辑,避免数据累加与内存泄漏

你使用on("value")持续监听数据变化,但每次回调都会往keyAreas里push数据且未清空旧数据,导致数组无限膨胀。同时组件卸载时未取消监听,会造成内存泄漏。

  • 每次监听回调执行前,先清空keyAreas
  • 组件卸载时调用监听返回的取消函数,终止监听
  • 通过watch监听user的变化,确保用户信息加载完成后再执行查询

2. 替换v-for的key为唯一标识

使用数组索引:key="index"会导致Vue在数组元素变化时复用错误的DOM节点,引发渲染异常。改用每个区域的title作为key,因为title是唯一且稳定的标识。

3. 处理异步用户数据

getUser返回的user是异步加载的,初始时user.value为null,直接访问user.value.uid会报错。通过watch监听user的变化,确保用户存在后再执行Firebase查询。

4. 补充缺失的updateChartData方法

模板中调用了updateChartData但代码未定义,这会导致控制台报错,中断页面渲染流程,需要实现该方法。


优化后的完整代码

<template>
  <div class="enquiry">
    <div class="row">
      <!-- 使用唯一的title作为v-for的key -->
      <div class="col-6" v-for="p in keyAreas" :key="p.title">
        <div class="card" style="margin-bottom: 10px">
          <div class="card-body">
            <h2 class="card-title">
              {{ p.number }}
              <span class="card-title" style="float: right">{{ p.title }}</span>
            </h2>
            <h5 class="card-text">
              Properties for rent
              <span class="card-title" style="float: right; margin-top: -5px">
                <Doughnut
                  :chart-data="updateChartData(p.number, totalPropertiesNumber)"
                  :width="80"
                  :height="80"
                />
              </span>
            </h5>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { ref, watch, onUnmounted } from "vue";
import { projectDatabase } from "../../firebase/config";
import getUser from "../../composables/getUser";
import {
  Chart as ChartJS,
  Title,
  Tooltip,
  Legend,
  ArcElement,
  CategoryScale,
} from "chart.js";

ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale);

export default {
  setup() {
    const { user } = getUser();
    const company = ref({});
    const keyAreas = ref([]);
    const totalPropertiesNumber = ref(0);
    let databaseListener = null;

    // 定义区域列表,无需用ref,因为不会修改原数组结构
    const allLGAs = [
      { title: "Abuja", number: 0 },
      { title: "Banana Island", number: 0 },
      { title: "Bluewaters Lagos", number: 0 },
      { title: "Benin City", number: 0 },
      { title: "Eko Atlantic", number: 0 },
    ];

    const filterLocation = (item, query, filter) => {
      return item[filter] === query;
    };

    // 实现模板中用到的图表数据更新方法
    const updateChartData = (current, total) => {
      return {
        labels: ["Current", "Remaining"],
        datasets: [{
          data: [current, total - current],
          backgroundColor: ["#36A2EB", "#FF6384"],
          hoverBackgroundColor: ["#36A2EB", "#FF6384"]
        }]
      };
    };

    // 监听user状态,确保用户加载完成后执行查询
    watch(user, (newUser) => {
      if (!newUser?.uid) return;

      // 移除之前的监听,避免重复触发
      if (databaseListener) {
        databaseListener();
      }

      // 绑定新的实时监听
      databaseListener = projectDatabase
        .ref("users")
        .child(newUser.uid)
        .child("company")
        .on("value", (snapshot) => {
          const companyData = snapshot.val() || {};
          company.value = companyData;

          // 计算总房产数量
          totalPropertiesNumber.value = Object.keys(companyData).length;

          // 清空旧数据,重新计算有效区域
          keyAreas.value = [];
          allLGAs.forEach((area) => {
            const count = Object.values(companyData)
              .filter(item => filterLocation(item, area.title, "location"))
              .length;
            
            if (count > 0) {
              // 复制对象,避免修改原数组元素
              keyAreas.value.push({ ...area, number: count });
            }
          });
        });
    }, { immediate: true });

    // 组件卸载时取消监听,防止内存泄漏
    onUnmounted(() => {
      if (databaseListener) {
        databaseListener();
      }
    });

    return {
      keyAreas,
      totalPropertiesNumber,
      updateChartData
    };
  },
};
</script>

额外注意事项

  • 如果不需要实时更新数据,可以将on("value")改为once("value"),避免持续监听带来的性能开销
  • 对大型数组进行过滤计算时,可以考虑使用computed属性,让Vue自动缓存计算结果,提升性能
  • 检查其他出现问题的页面是否存在类似的监听逻辑或key使用错误,统一修复

内容的提问来源于stack exchange,提问作者Deji James

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 01:55:18