vue3 keep-alive实现tab页面缓存
先上图
如何在我们切换tab标签的时候,缓存标签最后操作的内容,简单来说就是每个标签页中设置的比如搜索条件及结果、分页、新增、编辑等数据在切换回来的时候还能保持原样。
看看keep-alive是如何实现该功能的。
首先我们要了解keep-alive的基本使用。
具体介绍请查看官方文档(https://cn.vuejs.org/guide/built-ins/keep-alive.html#basic-usage)
这里有几个问题需要注意一下:
1、需要考虑页面共用的问题,如“新增/编辑”不是弹窗而是跳转页面,打开新增页面返回列表点击编辑页面,如果不做缓存清理跳转的将还是新增页面。
2、当页面关闭时再次打开如何清理之前的缓存。
废话不多说,上代码:
先创建一个处理缓存路由的文件 useRouteCache.ts
import { ref, nextTick, watch } from 'vue' import store from '../store'
import { useRoute } from 'vue-router'
const caches = ref<string[]>([]) let collect = false export default function useRouteCache() {
const storeState = store.state
const route = useRoute()
// 收集当前路由相关的缓存 function collectRouteCaches() { storeState.visitedView.forEach((routeMatch) => { const componentName: any = routeMatch?.name // 已打开的路由组件添加到缓存 if (!componentName) { return } addCache(componentName) }) } // 收集缓存(通过监听) function collectCaches() { if (collect) { return } collect = true watch(() => route.path, collectRouteCaches, { immediate: true }) } // 添加缓存的路由组件 function addCache(componentName: string | string[]) { if (Array.isArray(componentName)) { componentName.forEach(addCache) return } if (!componentName || caches.value.includes(componentName)) return caches.value.push(componentName) } // 移除缓存的路由组件 function removeCache(componentName: string | string[]) { if (Array.isArray(componentName)) { componentName.forEach(removeCache) return } const index = caches.value.indexOf(componentName) // if (index > -1) { return caches.value.splice(index, 1) } } // 移除缓存的路由组件的实例 async function removeCacheEntry(componentName: string) { if (removeCache(componentName)) { await nextTick() addCache(componentName) } } return { collectCaches, caches, addCache, removeCache, removeCacheEntry } }
然后在动态路由页面进行引入:
<template> <router-view v-slot="{ Component }"> <keep-alive :include="caches" :max="10">
<component :is="Component" :key="route.fullPath" />
</keep-alive> </router-view> </template> <script lang="ts"> import { defineComponent, onMounted } from 'vue' import useRouteCache from './hooks/useRouteCache'
import { useRoute } from 'vue-router'
export default defineComponent({ name: 'Main', setup() { const { caches } = useRouteCache()
const route = useRoute()
// 收集已打开路由tabs的缓存 const { collectCaches } = useRouteCache() onMounted(collectCaches) return { caches,
route
} } }) </script>
这里做的是菜单可配置的,也就是从后台读取的。如果是本地路由更简单,只需要在路由对象meta中加入keep属性,true表示当前路由需要缓存,false则不需要缓存
之前说的两个问题,这里说下解决办法:
在我们的tabbar(也就是tab标签)组件中,监听路由变化时进行判断,新增页面是不带参数的,编辑页带参数,通过这个进行缓存清除
watch: { const findItem: any = this.state.visitedView.find( (it) => it.name === newVal.name ) if ( findItem && newVal.name === findItem?.name && newVal.fullPath !== findItem?.fullPath ) { // 同一个路由,但是新旧路径不同时,需要清除路由缓存。例如route.path配置为 '/detail/:id'时路径会不同 removeCacheEntry(newVal.name) } else { addCache(newVal.name) } } }
还有就是当我们关闭tab页时清除路由缓存
removeTab(name) { const findItem: any = this.state.visitedView.find( (it) => it.fullPath === name ) if (findItem) { store.removeVisitedView(findItem).then((_) => { if (this.currentTab === name) { this.currentTab = this.state.visitedView[this.state.visitedView.length - 1].fullPath this.$router.push(this.currentTab) } }) // 同时移除tab缓存 removeCache(findItem.name || '') } }
这里的路由都是保存在store中,可根据自己项目进行相应的修改即可完成页面的缓存功能。
注意事项:
就是有时候我们已经做了页面缓存,但是切换的时候发现缓存没有生效,最后发现原来是缓存的组件名称和项目组件名称不一致导致的(名称大小写不一致) ,解决办法就是改成一致就可以生效了