Skip to main content

vue组件keepAlive不生效

遇到的问题

问题描述

有一个后台管理项目,页面中实现了多选项卡切换功能,但是在多个选项卡之间切换的时候,每次页面都会重置,无法保持当前页面的状态。比如在页面一中筛选了某一列表的数据,再切换到其他页面再切换回来的时候,页面一中的筛选内容都会重置,影响用户的使用体验。

排查解决问题

  1. 排查<keep-alive>标签的位置,以vue-element-admin为例,<keep-alive>标签位于 layout 布局中,也就是说加载到布局中的下一级的组件,能够保持状态。如果路由嵌套大于 2 级,那么就需要将<keep-alive>加到 layout 下级的组件中。

  2. 看看当前代码的写法是否正确,并且需要结合当前 vue 的版本和 vue-router 的版本来看。示例(vue3):

<!-- 错误写法 -->
<template>
  <keep-alive>
    <router-view v-slot="{ Component }">
      <component :is="Component" />
    </router-view>
  </keep-alive>
</template>
<!-- 正确写法 -->
<template>
  <router-view v-slot="{ Component }">
    <keep-alive>
      <component :is="Component" />
    </keep-alive>
  </router-view>
</template>

补充

通过上面代码在页面中实现多个选项卡组件状态缓存之后,出现另外一个组件复用的问题。比如要展示一个商品详情页,用的是同一个组件但是传入的商品id不一样,因为组件的name是固定的,所以切换不同商品详情页面时页面不刷新。

解决办法:在组件中指定一个key,这个key的值就是当前页面的fullPath,当key改变的时候,组件就会强制刷新。

<template>
  <router-view v-slot="{ Component }">
    <keep-alive :include="cachedViews" :max="30">
      <component :is="Component" :key="key" />
    </keep-alive>
  </router-view>
</template>
<script>
export default {
  name: "MainPage",
  computed: {
    cachedViews() {
      return this.$store.state.tagsView.cachedViews;
    },
    key() {
      return this.$route.fullPath;
    },
  },
};
</script>

keepAlive 使用方法

简介

<KeepAlive> 是一个内置组件,它的功能是在多个组件间动态切换时缓存被移除的组件实例。

基本用法

<!-- 切换组件时,包含在keep-alive标签中的组件状态会保存 -->
<template>
  <keep-alive>
    <component :is="name"></component>
  </keep-alive>
</template>

配合路由实现页面多选项卡状态保持

<!-- 核心代码 -->
<template>
  <router-view v-slot="{ Component }">
    <keep-alive>
      <component :is="Component" />
    </keep-alive>
  </router-view>
</template>

延申:vue 中的路由

import { createRouter, createWebHashHistory } from "vue-router";
import Layout from "../layout";
const routes = [
  {
    path: "/",
    name: "Home",
    /* 渲染到第一级<router-view /> 标签中,通常是App.vue */
    component: Layout,
    redirect: "/index",
    meta: {
      title: "首页",
    },
    children: [
      {
        path: "index",
        name: "HomePage",
        /* 渲染到父级组件的<router-view />标签中,也就是Layout中,所有子级路由以此类推 */
        component: () => import("../views/Home.vue"),
        meta: {
          title: "首页",
        },
      },
      {
        path: "pageA",
        name: "PageA",
        component: () => import("../views/PageA.vue"),
        meta: {
          title: "页面A",
        },
      },
      {
        path: "pageB",
        name: "PageB",
        component: () => import("../views/PageB.vue"),
        meta: {
          title: "页面B",
        },
      },
    ],
  },
];
const router = createRouter({
  //history: createWebHistory(),
  history: createWebHashHistory(),
  routes,
});
export default router;