Vue3使用KeepAlive实现页面缓存

659 阅读2分钟

需求示例:

image.png

代码实现:

参见文档: KeepAlive

在App.vue中:

<template>
  <router-view v-slot="{ Component }">
    <keep-alive :include="include">
      <component
        v-if="route.meta.keepAlive"
        :key="route.name"
        :is="Component"
      />
    </keep-alive>
    <component v-if="!route.meta.keepAlive" :key="route.name" :is="Component" />
  </router-view>
</template>
<script setup>
import { ref } from "vue";
import { useRoute, useRouter } from "vue-router";

const route = useRoute();
const router = useRouter();
const include = ref([]);

router.beforeEach((to, from, next) => {
  // 如果要进入的页面需要 keepAlive 缓存,将 name 添加到 include 数组中,router中的name和组件中的name要一致!
  if (to.meta.keepAlive) {
    if (!include.value.includes(to.name)) {
      include.value.push(to.name);
    }
  }
  // 如果要离开的页面是 keepAlive 缓存的,根据 deepth 判断是前进还是后退
  // 如果是后退,则清除keepAlive缓存
  if (from.meta.keepAlive && to.meta.deepth < from.meta.deepth) {
    const index = include.value.indexOf(from.name);
    if (index !== -1) {
      include.value.splice(index, 1);
    }
  }
  next();
});
</script>

注意:

  1. router.js中要在meta中表明keepAlive和deepth。
  2. include变量包含的name是组件的name,不是router中的name,要在组件中声明name。router中的name和组件中的name要一致!
import { defineOptions } from "vue";
defineOptions({ name: "alivePage" });
  1. 被缓存的页面可以使用onActivatedonDeactivated两个生命周期钩子,onMounted 是组件挂载到 DOM 上时触发的,只会在组件首次加载时调用一次。 onActivated 是针对被 keep-alive 缓存的组件,当组件从非激活状态变为激活状态时调用,包括第一次激活时。因为第一次进入页面onActivatedonMounted都会被执行,所以要特别注意两个钩子中放置的逻辑,避免重复。

建议处理方式

  • 如果逻辑只需在组件激活时执行,不区分首次还是后续激活,比如在详情页可以提交表单修改信息,再回到列表页还要像第一次进入时调用列表查询接口,那么可以将逻辑放在 onActivated 中,就不需要onMounted了。
  • 如果逻辑需要区分首次挂载和激活后的情况,比如列表的查询只在初始化时进行,建议结合 onMounted 和 onActivated,通过标志位来处理:
import { ref, onMounted, onActivated } from 'vue';

const isInitialized = ref(false);

onMounted(() => {
    if (!isInitialized.value) {
        console.log('首次挂载执行');
        // 放置只需执行一次的初始化逻辑
        isInitialized.value = true;
    }
});

onActivated(() => {
    console.log('组件激活时执行');
    // 放置每次激活时都需要执行的逻辑
});