Nb
Study
.com
🔍 请输入搜索关键字

Vue3 中KeepAlive在嵌套路由中的使用及注意事项

nbstudy 发表于 2025-03-29 22:44:30

<KeepAlive> 是一个内置组件,它的功能是在多个组件间动态切换时缓存被移除的组件实例。通过缓存不活动的组件实例,避免重复渲染。通常在动态组件或者路由组件中使用,可以保留组件状态或者提高性能。

假设router/index.js 如下:

javascript 复制代码
const routes = [
  {
    path: '/',
    component: () => import('../layouts/MainLayout.vue'),
    children: [
      {
        path: '/parent',
        component: () => import('../views/ParentView.vue'), // 父组件
        children: [
          {
            path: 'child1',
            component: () => import('../views/Child1.vue'),
            meta: { keepAlive: true } // 启用缓存
          },
          {
            path: 'child2',
            component: () => import('../views/Child2.vue')
          }
        ]
      }
    ]
  }
]

其中 App.vueMainLayout 中都有router-view 组件。该如何配置 keepalive呢?

代码如下:

App.vue 配置

html 复制代码
<!-- App.vue -->
<template>
  <!-- 注意在嵌套路由中使用 keep-alive -->
  <router-view  v-slot="{ Component }">
    <keep-alive :include="['MainLayout']">
      <component :is="Component" />
    </keep-alive>
  </router-view >
</template>

MainLayout.vue 配置

javascript 复制代码
<template>
<el-scrollbar class="flex-1 layout-main-content">
  <div class="flex-1 shadow bg-white p-3">
    <router-view v-slot="{ Component }" >
        <keep-alive :include="cachedRoutes">
          <component :is="Component" />
        </keep-alive>
      </router-view>
  </div>
</el-scrollbar>
</template>
<script lang="ts" setup>
const router = useRouter();
// 动态计算需要缓存的路由名称
const cachedRoutes = computed(() => {
  let arr =  router.getRoutes().filter((r) => r.meta?.keepAlive).map(r =>r.name);  
  // 过滤掉 undefined 值
  const validRoutes = arr.filter((name): name is string => name !== undefined);
  return validRoutes;
});
</script>

注意事项

component中了key的使用

如果component 中使用了key,可能会造成重复渲染,axios 多次请求。

javascript 复制代码
<component :is="Component" :key="$route.fullPath"/>

可以修改key的绑定或删除key,以生成稳定 Key。

javascript 复制代码
<!-- 修改后 -->
<component :is="Component" 
  :key="`${$route.name}-${JSON.stringify($route.params)}`"/>

生命周期

keepAlive组件特有的生命周期,可用于调试或进行智能缓存策略控制。

javascript 复制代码
onActivated(() => console.log('Activated'))
onDeactivated(() => console.log('Deactivated'))

如何灵活控制请求执行条件?

javascript 复制代码
<script setup>
import { ref, watch, onActivated } from 'vue'
import { useRoute } from 'vue-router'

const route = useRoute()
const data = ref(null)
const hasLoaded = ref(false) // 请求状态标记

// 统一请求方法
const fetchData = async () => {
  if (hasLoaded.value) return
  try {
    const res = await axios.get(`/api/data/${route.params.id}`)
    data.value = res.data
    hasLoaded.value = true
  } catch (err) {
    console.error(err)
  }
}

// 常规加载
if (!hasLoaded.value) {
  fetchData()
}

// 监听路由参数变化
watch(() => route.params.id, (newVal, oldVal) => {
  if (newVal !== oldVal) {
    hasLoaded.value = false
    fetchData()
  }
})

// 缓存激活时刷新数据
onActivated(() => {
  if (Date.now() - lastLoadTime > 5 * 60 * 1000) { // 5分钟缓存
    hasLoaded.value = false
    fetchData()
  }
})
</script>