【vue】聊一聊嵌套路由使用keep-alive缓存的实现

shy帅宸

共 3904字,需浏览 8分钟

 ·

2024-04-10 15:27

背景

大家应该都写过类似下图布局的页面,一个顶部导航、一个侧边菜单和一个主要内容区域。其中只有主要内容区域是变化。在这个基础上实现缓存大家应该都有经历过。只要在 router-view 上使用 keep-alive 标签就可以轻松实现缓存。但是在多层嵌套的 router-view 中,只能缓存到该层下的 router-view 。针对上面的情况下面聊聊我的实现。(以下内容都是基于Vue3 + pinia 实现) 

091c2e23e3abb6f489d681706aade305.webp

路由层级扁平化

搜索网上的方案大部分都是说将路由层级扁平化,直白点就是在路由守卫中将route对象的matched属性将使用到router-view的组件进行删除,将路由层级提升,从而实现缓存的目的。这种方案可行,但是不能适用于所有情况。如果路由组件中存在布局(如下图),那该方案会将会丢失这部分(红色框内)内容。 265506473fa858271c0d5697b571ecc4.webp

所有 router-view 都使用 keep-alive (推荐)

既然 keep-alive 无法多层嵌套缓存,那我们可以换个思路,将每个 router-view 都使用 keep-alive ,通过 include 属性来判断组件是否需要进行缓存。

重新封装 router-view 组件

我们必然不会只在一处使用 router-view ,那我们就需要对 router-view 组件进行二次封装。举例代码如下

    

vue

<script setup>
import { computed } from 'vue'
import { useRouteCacheStore } from '@/stores/modules/route-cache'

defineProps({
keepalive: {
type: Boolean,
default: () => false
}
})

const routeCacheStore = useRouteCacheStore()

const keepalives = computed(() => routeCacheStore.keepalives)

</script>

<template>
<router-view v-slot="{ Component }">
<keep-alive :include="keepalives" v-if="keepalive">
<component :is="Component" />
</keep-alive>
<component :is="Component" v-else />
</router-view>
</template>

代码中的 keepalives 就是需要缓存组件名称的数组,一般情况下我们都是放在 pinia 或者 vuex 中。

    

js

import { defineStore } from 'pinia'

export const useRouteCacheStore = defineStore('routeCache', {
state: () => ({
keepalives: ['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight'],
})
})

路由层级

9eeb8866b3f2030514d41deb4d5347e9.webp

 如上图:路由一、二、三为同级路由,其中路由三为使用router-view的组件。路由三下的路由四、五、六也为同级路由,其中路由六为使用router-view的组件。路由六下的路由七、八也为同级路由。嵌套路由层级代码如下

    

js

{
path: '/route-cache',
name: 'routeCache',
redirect: { name: 'routeCacheOne' },
component: () => import('../views/route-cache/index.vue'),
children: [
{
path: '/one',
name: 'routeCacheOne',
component: () => import('../views/route-cache/views/one/index.vue')
},
{
path: '/two',
name: 'routeCacheTwo',
component: () => import('../views/route-cache/views/two/index.vue')
},
{
path: '/three',
name: 'routeCacheThree',
redirect: { name: 'routeCacheFour' },
component: () => import('../views/route-cache/views/three/index.vue'),
children: [
{
path: '/four',
name: 'routeCacheFour',
component: () => import('../views/route-cache/views/four/index.vue')
},
{
path: '/five',
name: 'routeCacheFive',
component: () => import('../views/route-cache/views/five/index.vue')
},
{
path: '/six',
name: 'routeCacheSix',
redirect: { name: 'routeCacheSeven' },
component: () => import('../views/route-cache/views/six/index.vue'),
children: [
{
path: '/seven',
name: 'routeCacheSeven',
component: () => import('../views/route-cache/views/Seven/index.vue')
},
{
path: '/eight',
name: 'routeCacheEight',
component: () => import('../views/route-cache/views/eight/index.vue')
},
]
},
]
},
]
}

注意

如上图的结构,如果所有组件都需要缓存那 keepalives 数组应该等于['One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight'], 而不是['One', 'Two', 'Four', 'Five', 'Seven', 'Eight']。简单的说就是使用 router-view 的组件(即路由三、路由六)也需要给组件命名并记录到 keepalives 数组中。如果不这么做的话会导致出现部分情况不缓存: 

1c6600c098fda162d8c16c4eaa644c1d.webp

完整演示

6c540414505c5c829657c9ff22c9a9db.webp

以上就是本次分享的内容,附上 源码

感谢看官看到这里,如果觉得文章不错的话,可以给小生的几个开源项目点个Star⭐!

  • 基于 Vue3 + Element-plus 管理后台基础功能框架

    • 预览: https://admin.gumingchen.icu

    • Github: https://github.com/gmingchen/agile-admin

    • Gitee: https://gitee.com/shychen/agile-admin

    • 基础版后端: https://github.com/gmingchen/java-spring-boot-admin

    • 文档: https://admin.gumingchen.icu/doc/

  • 基于 Vue3 + Element-plus + websocket 即时聊天系统

    • 预览: http://im.gumingchen.icu

    • 代码: https://github.com/gmingchen/vue3-element-plus-im

    • 后端代码: https://github.com/gmingchen/java-im

  • 基于 node 开发的后端服务: https://github.com/gmingchen/node-server


浏览 14
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报