fix iOS back transition

This commit is contained in:
Timi
2026-04-14 15:47:03 +08:00
parent 42efa2b370
commit 11c1199449
5 changed files with 74 additions and 13 deletions

View File

@@ -14,6 +14,7 @@
import type { RouteLocationNormalized } from "vue-router";
import { viewDepthKey } from "vue-router";
import { useGlobalUIStore } from "@/store/globalUIStore";
import { hasProgrammaticBackNavigation } from "@/utils/backNavigationSignal";
defineOptions({
name: "PageTransition"
@@ -26,6 +27,8 @@ const viewDepth = inject(viewDepthKey, 0);
const transitionName = ref("");
const hasTransition = ref(false);
// iOS 左滑返回由系统接管,页面侧不应叠加离场动画。
const isIOS = /iP(ad|hone|od)/i.test(window.navigator.userAgent);
const pageBackground = computed(() => globalUIStore.bodyBackground);
const currentDepth = computed(() => Number(unref(viewDepth)));
const pageKey = computed(() => {
@@ -72,6 +75,17 @@ const unregisterGuard = router.beforeEach((to, from) => {
const toDepth = calcDepth(to);
const fromDepth = calcDepth(from);
const isBackwardNavigation = toDepth < fromDepth;
// 主动触发的返回(如导航栏返回)保留动画。
const isProgrammaticBack = hasProgrammaticBackNavigation();
// 仅在 iOS 系统返回手势下关闭动画。
const shouldDisableTransition = isIOS && isBackwardNavigation && !isProgrammaticBack;
if (shouldDisableTransition) {
transitionName.value = "";
hasTransition.value = false;
return;
}
if (fromDepth < toDepth) {
transitionName.value = "push-left";

View File

@@ -129,33 +129,29 @@ function resolveTabValue(path: string): string {
if (path === "/" || path.startsWith("/files/")) {
return "/";
}
return path;
}
watch(
() => route.path,
(newPath: string) => {
tabVal.value = resolveTabValue(newPath);
},
{ immediate: true }
);
watch(() => route.path, (newPath: string) => {
tabVal.value = resolveTabValue(newPath);
}, { immediate: true });
function onChangeTab(value: string): void {
async function onChangeTab(value: string): Promise<void> {
if (value === "__music__") {
musicPlayerStore.setPopupVisible(true);
tabVal.value = resolveTabValue(route.path);
return;
}
router.push(value);
if (resolveTabValue(route.path) === value) {
return;
}
await router.replace(value);
}
const isTabBarPaddingNeeded = computed(() => {
if (!tabBarStore.isShowing) {
return false;
}
return route.meta.tabBarPadding !== false;
});
@@ -163,7 +159,6 @@ const tabBarPadding = computed(() => {
if (isTabBarPaddingNeeded.value) {
return "6rem";
}
return "0rem";
});

View File

@@ -91,6 +91,7 @@ function saveConnect(): void {
theme: "success",
message: "连接配置已保存"
});
router.back();
}
onMounted(() => {

View File

@@ -14,6 +14,10 @@ import ServerDetail from "@/pages/dashboard/ServerDashboard/ServerDetail.vue";
import ServerPerformanceDetail from "@/pages/dashboard/ServerDashboard/ServerPerformanceDetail.vue";
import ServerPartitionsDetail from "@/pages/dashboard/ServerDashboard/ServerPartitionsDetail.vue";
import DockerContainerDetail from "@/pages/dashboard/DockerDashboard/DockerContainerDetail.vue";
import {
clearProgrammaticBackNavigation,
markProgrammaticBackNavigation
} from "@/utils/backNavigationSignal";
const router = createRouter({
history: createWebHistory("/"),
@@ -180,6 +184,23 @@ const router = createRouter({
]
});
const rawBack = router.back.bind(router);
const rawGo = router.go.bind(router);
// 全局代理:所有代码触发的后退都自动标记为“主动返回”。
router.back = () => {
markProgrammaticBackNavigation();
rawBack();
};
// 覆盖 go(-1 / -n) 场景,保证与 back() 行为一致。
router.go = (delta) => {
if (delta < 0) {
markProgrammaticBackNavigation();
}
rawGo(delta);
};
router.beforeEach((to: RouteLocationNormalized) => {
const settingStore = useSettingStore();
@@ -200,6 +221,8 @@ router.beforeEach((to: RouteLocationNormalized) => {
});
router.afterEach((to: RouteLocationNormalized) => {
// 一次导航结束后清理信号,防止影响后续动画判定。
clearProgrammaticBackNavigation();
const globalUIStore = useGlobalUIStore();
const targetBackground = typeof to.meta.bodyBackground === "string" ? to.meta.bodyBackground : DEFAULT_BODY_BACKGROUND;
globalUIStore.setBodyBackground(targetBackground);

View File

@@ -0,0 +1,28 @@
let programmaticBackAt = 0;
// 主动返回信号有效期,避免历史信号污染后续导航
const PROGRAMMATIC_BACK_SIGNAL_TTL_MS = 1200;
// 由代码触发 router.back / router.go(-1) 时打标
export function markProgrammaticBackNavigation(): void {
programmaticBackAt = Date.now();
}
// 读取主动返回信号,超时后自动清理
export function hasProgrammaticBackNavigation(): boolean {
if (programmaticBackAt < 1) {
return false;
}
const hasSignal = Date.now() - programmaticBackAt <= PROGRAMMATIC_BACK_SIGNAL_TTL_MS;
if (!hasSignal) {
programmaticBackAt = 0;
}
return hasSignal;
}
// 在导航结束后统一清理信号
export function clearProgrammaticBackNavigation(): void {
programmaticBackAt = 0;
}