不多bb,上效果
- 支持页面层级缓存。打开的所有二级三级页面都通过keepAlive缓存
- 关闭页面后,销毁对应页面缓存。如三级页面返回至一级页面,则二级和三级页面删除缓存
- 支持页面跳转效果。通过transition搭配v-show与页面缓存实现
不过bb,上代码
<script setup lang="ts">
import { type RouteLocationRaw, RouterView, useRouter } from "vue-router";
import { computed, ref, watch, type Ref, nextTick } from "vue";
const cacheList: Ref<string[][]> = ref([[]]);
const action = ref<"push" | "replace" | "go" | "back" | "forward">("push");
const router = useRouter();
const pageTransition = ref({
pageEnterName: "fade-transition",
pageLeaveName: "fade-transition",
});
const pageTransitionClass = computed(() => {
return {
enterFromClass: `${pageTransition.value.pageEnterName}-enter-from`,
enterActiveClass: `${pageTransition.value.pageEnterName}-enter-active`,
enterToClass: `${pageTransition.value.pageEnterName}-enter-to`,
leaveFromClass: `${pageTransition.value.pageLeaveName}-leave-from`,
leaveActiveClass: `${pageTransition.value.pageLeaveName}-leave-active`,
leaveToClass: `${pageTransition.value.pageLeaveName}-leave-to`,
};
});
const pageLevel = ref(0); //页面进深层级
const afterPageLevel = ref(0); //等页面跳转后更新至pageLevel,为了优化动画的显示
const pageShow = ref(true);
watch(afterPageLevel, (newPageLevel, oldPageLevel) => {
if (newPageLevel > oldPageLevel) {
pageTransition.value = {
pageEnterName: "slide-x-reverse-transition",
pageLeaveName: "fade-transition",
};
} else {
pageTransition.value = {
pageEnterName: "",
pageLeaveName: "slide-x-reverse-transition",
};
}
});
router.beforeEach((to, from, next) => {
if (action.value == "replace") {
pageLevel.value = afterPageLevel.value;
next();
const toName = to.name as string;
if (toName) {
const levelCacheList = cacheList.value[cacheList.value.length - 1]; //当前层级的页面缓存列表
if (!levelCacheList.includes(toName)) {
levelCacheList.push(toName);
}
} else {
console.warn(to, "route未定义name属性,不能缓存");
}
return;
}
pageShow.value = false;
const backNum = pageLevel.value - afterPageLevel.value;
const isEnter = backNum <= 0;
setTimeout(
() => {
if (backNum > 0) {
cacheList.value = cacheList.value.slice(
0,
cacheList.value.length - backNum,
);
} else if (backNum < 0) {
for (let i = 0; i < -backNum; i++) {
cacheList.value.push([]);
}
}
if (cacheList.value.length == 0) {
cacheList.value.push([]);
}
pageLevel.value = afterPageLevel.value;
nextTick(() => {
next();
const toName = to.name as string;
if (toName) {
const levelCacheList = cacheList.value[cacheList.value.length - 1]; //当前层级的页面缓存列表
if (!levelCacheList.includes(toName)) {
levelCacheList.push(toName);
}
} else {
console.warn(to, "route未定义name属性,不能缓存");
}
setTimeout(
() => {
pageShow.value = true;
},
isEnter ? 200 : 70,
);
});
},
isEnter ? 200 : 250,
);
});
const routerGo = router.go;
router.go = (n: number) => {
action.value = "go";
afterPageLevel.value += n;
routerGo(n);
};
const routerPush = router.push;
router.push = (to: RouteLocationRaw) => {
action.value = "push";
afterPageLevel.value++;
return routerPush(to);
};
const routerReplace = router.replace;
router.replace = (to: RouteLocationRaw) => {
action.value = "replace";
return routerReplace(to);
};
const routerBack = router.back;
router.back = () => {
action.value = "back";
afterPageLevel.value--;
return routerBack();
};
const routerForward = router.forward;
router.forward = () => {
action.value = "forward";
afterPageLevel.value++;
return routerForward();
};
</script>
<template>
<router-view v-slot="{ Component, route }">
<transition
:enterFromClass="pageTransitionClass.enterFromClass"
:enterActiveClass="pageTransitionClass.enterActiveClass"
:enterToClass="pageTransitionClass.enterToClass"
:leaveFromClass="pageTransitionClass.leaveFromClass"
:leaveActiveClass="pageTransitionClass.leaveActiveClass"
:leaveToClass="pageTransitionClass.leaveToClass"
mode="out-in"
>
<div v-show="pageShow" v-if="cacheList.length > 0">
<div
v-for="(levelCacheList, index) in cacheList"
v-show="index >= cacheList.length - 1"
>
<keep-alive>
<component
:is="
levelCacheList.includes(route.name as string) ? Component : null
"
/>
</keep-alive>
</div>
</div>
</transition>
</router-view>
</template>
<style scoped></style>
不多bb,关注一下
小王的个人博客