add FileExplorerPage

This commit is contained in:
Timi
2026-04-03 13:43:31 +08:00
parent 2665acc885
commit ded231671a
8 changed files with 519 additions and 93 deletions

View File

@@ -1,20 +1,18 @@
<template>
<div class="page-transition">
<router-view v-slot="{ Component }">
<transition v-if="hasTransition" :name="transitionName">
<div class="pages" :key="route.fullPath">
<transition :name="transitionName" :css="hasTransition">
<div class="pages" :key="pageKey">
<component :is="Component" />
</div>
</transition>
<div v-else class="pages" :key="route.fullPath">
<component :is="Component" />
</div>
</router-view>
</div>
</template>
<script lang="ts" setup>
import type { RouteLocationNormalized } from "vue-router";
import { viewDepthKey } from "vue-router";
import { useGlobalUIStore } from "@/store/globalUIStore";
defineOptions({
@@ -24,12 +22,26 @@ defineOptions({
const router = useRouter();
const route = useRoute();
const globalUIStore = useGlobalUIStore();
const viewDepth = inject(viewDepthKey, 0);
const transitionName = ref("push-left");
const hasTransition = computed(() => transitionName.value !== "");
const transitionName = ref("");
const hasTransition = ref(false);
const pageBackground = computed(() => globalUIStore.bodyBackground);
const currentDepth = computed(() => Number(unref(viewDepth)));
const pageKey = computed(() => {
const depth = currentDepth.value;
const matchedRecord = route.matched[depth];
// ---------- 路由深度计算 ----------
if (!matchedRecord) {
return route.fullPath;
}
if (depth < route.matched.length - 1) {
return matchedRecord.path;
}
return route.fullPath;
});
const pathCache = new Map<string, number>();
@@ -51,17 +63,25 @@ function calcDepth(sourceRoute: RouteLocationNormalized): number {
return depth;
}
// beforeEach 返回注销函数,组件卸载时必须调用,否则守卫会一直存在。
const unregisterGuard = router.beforeEach((to, from) => {
if (to.meta.tabBarVisible && from.meta.tabBarVisible) {
transitionName.value = "";
hasTransition.value = false;
return;
}
const toDepth = calcDepth(to);
const fromDepth = calcDepth(from);
if (fromDepth < toDepth) {
transitionName.value = "push-left";
hasTransition.value = true;
} else if (toDepth < fromDepth) {
transitionName.value = "push-right";
hasTransition.value = true;
} else {
transitionName.value = "";
hasTransition.value = false;
}
});
@@ -84,28 +104,35 @@ onUnmounted(() => {
position: relative;
overflow-x: hidden;
// 这个 wrapper 必须独立,不能把 class=pages 直接挂在 <component> 上。
// 否则页面根节点会和动画容器变成同一个 DOM 节点,容易导致 fixed 布局溢出视口。
.pages {
inset: 0;
height: 100%;
position: absolute;
background: v-bind(pageBackground);
overflow-x: hidden;
}
// ---------- push-left / push-right 公共过渡状态 ----------
.push-left-enter-active,
.push-left-leave-active,
.push-right-enter-active,
.push-right-leave-active {
inset: 0;
width: 100%;
height: 100%;
position: fixed;
position: absolute;
transition: transform @duration @easing, opacity .2s linear;
backface-visibility: hidden;
}
// ---------- 前进:下一页从右滑入,当前页退到左侧 ----------
.push-left-enter-active,
.push-right-leave-active {
z-index: 2;
}
.push-left-leave-active,
.push-right-enter-active {
z-index: 1;
}
.push-left-enter-from {
transform: translate3d(100%, 0, 0);
@@ -125,10 +152,7 @@ onUnmounted(() => {
transform: translate3d(-@page-offset, 0, 0);
}
// ---------- 返回:当前页从右滑出,上一页回到原位 ----------
.push-right-enter-active {
z-index: -1;
transition: transform @duration @easing, opacity .3s;
}