feat: 添加页面切换动画

This commit is contained in:
2026-05-23 23:08:00 +08:00
parent fc71e924e7
commit bc785ac1ce
7 changed files with 106 additions and 4 deletions
+60
View File
@@ -24,3 +24,63 @@ useHead({
</NuxtLayout>
</div>
</template>
<style scoped>
.slide-left-enter-active,
.slide-left-leave-active,
.slide-right-enter-active,
.slide-right-leave-active {
transition:
opacity 0.2s ease-in-out,
transform 0.2s ease-in-out;
}
/* 前进:新页面从右侧滑入 */
.slide-left-enter-from {
opacity: 0;
transform: translateX(32px);
}
.slide-left-enter-to {
opacity: 1;
transform: translateX(0);
}
/* 前进:旧页面向左消失 */
.slide-left-leave-from {
opacity: 1;
transform: translateX(0);
}
.slide-left-leave-to {
opacity: 0;
transform: translateX(-32px);
}
/* 后退:新页面从左侧滑入 */
.slide-right-enter-from {
opacity: 0;
transform: translateX(-32px);
}
.slide-right-enter-to {
opacity: 1;
transform: translateX(0);
}
/* 后退:旧页面向右消失 */
.slide-right-leave-from {
opacity: 1;
transform: translateX(0);
}
.slide-right-leave-to {
opacity: 0;
transform: translateX(32px);
}
@media (prefers-reduced-motion: reduce) {
.slide-left-enter-active,
.slide-left-leave-active,
.slide-right-enter-active,
.slide-right-leave-active {
transition: none;
}
}
</style>
+10
View File
@@ -0,0 +1,10 @@
// app/middleware/page-transition.global.ts - 根据页面 pageOrder 动态切换滑动方向
// 离开动画依赖 from.meta,进入动画依赖 to.meta,需要同时设置才能保证方向一致
export default defineNuxtRouteMiddleware((to, from) => {
const toOrder = Number(to.meta.pageOrder ?? 0);
const fromOrder = Number(from.meta.pageOrder ?? 0);
const name = toOrder >= fromOrder ? "slide-left" : "slide-right";
to.meta.pageTransition = { name };
from.meta.pageTransition = { name };
});
+5 -1
View File
@@ -5,7 +5,11 @@ import QaRecordsTable from "@/components/dashboard/QaRecordsTable.vue";
import StatsOverview from "@/components/dashboard/StatsOverview.vue";
import { useAnswerStore } from "@/stores/answer";
definePageMeta({ middleware: "auth" });
definePageMeta({
middleware: "auth",
pageOrder: 2,
pageTransition: { name: "slide-left" }
});
const answerStore = useAnswerStore();
+5
View File
@@ -4,6 +4,11 @@ import AnswerForm from "@/components/home/AnswerForm.vue";
import AnswerResult from "@/components/home/AnswerResult.vue";
import OcsConfigCard from "@/components/home/OcsConfigCard.vue";
definePageMeta({
pageOrder: 1,
pageTransition: { name: "slide-left" }
});
useHead({
title: "OCS AI 答题服务"
});
+11 -2
View File
@@ -15,6 +15,11 @@ import {
import { Input } from "@/components/ui/input";
import { useAuthStore } from "@/stores/auth";
definePageMeta({
pageOrder: 3,
pageTransition: { name: "slide-left" }
});
useHead({ title: "登录 - OCS AI 答题服务" });
const authStore = useAuthStore();
@@ -30,7 +35,9 @@ const formSchema = toTypedSchema(
.string({ required_error: "邮箱不能为空" })
.min(1, "邮箱不能为空")
.email("请输入有效的邮箱地址"),
password: z.string({ required_error: "密码不能为空" }).min(1, "密码不能为空")
password: z
.string({ required_error: "密码不能为空" })
.min(1, "密码不能为空")
})
);
@@ -91,7 +98,9 @@ const onSubmit = handleSubmit(async (values) => {
<Button
type="submit"
:disabled="isSubmitting || authStore.loading || !authStore.initialized"
:disabled="
isSubmitting || authStore.loading || !authStore.initialized
"
class="w-full"
>
{{ authStore.loading ? "登录中..." : "登录" }}
+8 -1
View File
@@ -15,6 +15,11 @@ import {
import { Input } from "@/components/ui/input";
import { useAuthStore } from "@/stores/auth";
definePageMeta({
pageOrder: 4,
pageTransition: { name: "slide-left" }
});
useHead({ title: "注册 - OCS AI 答题服务" });
const authStore = useAuthStore();
@@ -115,7 +120,9 @@ const onSubmit = handleSubmit(async (values) => {
<Button
type="submit"
:disabled="isSubmitting || authStore.loading || !authStore.initialized"
:disabled="
isSubmitting || authStore.loading || !authStore.initialized
"
class="w-full"
>
{{ authStore.loading ? "注册中..." : "注册" }}
+7
View File
@@ -6,6 +6,13 @@ export default defineNuxtConfig({
compatibilityDate: "2025-07-15",
devtools: { enabled: true },
app: {
pageTransition: {
name: "slide-left",
mode: "out-in"
}
},
css: ["~/assets/css/tailwind.css"],
vite: {