路由缓存方案
vue3 中如何使用 vue-router 优雅的实现路由缓存
页面缓存覆盖的场景
首页
└── a 页面
└── b 页面
└── c 页面
- 首页
- 从 a|b 页面返回 要缓存
- a 页面
- 不要缓存
- b 页面
- 从 c 页面返回 要缓存
- c 页面
- 不要缓存
演示
设计思路
- 缓存与进入页面的路径有关,因此需要知道页面的来源。从路由的
beforeEach中获取。 - 中间页面要缓存的都设置
keepAlive为true - 再通过
includeName、excludeName配置路径名,做额外的刷新处理
缓存各个步骤实现
路由缓存
<template>
<routerView v-slot="{ Component }">
<keep-alive>
<component
:is="Component"
:key="$route.name"
v-if="$route.meta.keepAlive"
/>
</keep-alive>
<component
:is="Component"
:key="$route.name"
v-if="!$route.meta.keepAlive"
/>
</routerView>
</template>
<script setup>
import { RouterLink, RouterView } from "vue-router";
</script>
- meta.keepAlive
获取页面来源
// 进入路由前
router.beforeEach((to, from, next) => {
setRouteCache(to, from);
next();
});
// 路由缓存
function setRouteCache(to, from) {
let toMeta = to.meta || {};
to.meta = Object.assign(
{ keepAlive: toMeta.includeName || toMeta.excludeName },
toMeta,
{
fromName: from.name,
}
);
}
- 通过
beforeEach获取,并将来源存储在fromName字段
路由配置
routes: [
{
path: "/",
name: "home",
component: HomeView,
meta: {
excludeName: ["a", "b"], // 只要不是 a|b 页面 ,都要刷新
},
},
{
path: "/a",
name: "a",
component: () => import("../views/A.vue"),
meta: {
excludeName: "b", // 只要不是 b 页面 ,都要刷新
},
},
{
path: "/b",
name: "b",
component: () => import("../views/B.vue"),
meta: {
includeName: "home", // 只有是 home 页面 ,才要刷新。
},
},
{
path: "/c",
name: "c",
component: () => import("../views/C.vue"),
},
],
- 不需要缓存的页面,不需要配置
- 只有哪个来源的页面才刷新,配置
includeName - 除了哪个来源的页面才刷新,配置
excludeName includeName、excludeName,支持字符串与数组,根据实际情况自由结合也可以
组合式函数
import { onMounted, onActivated } from "vue";
import { useRoute } from "vue-router";
// 路由更新
export function useRouteRefresh(refreshFn) {
let active = false; // 防止多次触发
// 是否为字符串
const isString = (val) => typeof includeName === "string";
onMounted(() => {
active = true;
refreshFn && refreshFn();
});
onActivated(() => {
const route = useRoute();
if (active) {
active = false;
return;
}
if (!refreshFn) return;
let { fromName, includeName, excludeName } = route.meta;
// 页面重新刷新
if (!fromName) return refreshFn();
// 包含的路由,包含就刷新
if (includeName) {
if (isString(includeName) && includeName === fromName) return refreshFn();
if (includeName.includes(fromName)) return refreshFn();
}
// 排除的路由,不包含就刷新
if (excludeName) {
if (isString(excludeName) && excludeName !== fromName) return refreshFn();
if (!excludeName.includes(fromName)) return refreshFn();
}
});
}
页面引入组合式函数
import { useRouteRefresh } from "./../hooks/route";
// 刷新的时候才会执行的函数
useRouteRefresh(() => {
console.log("页面 刷新处理");
});