feat: 🎉新增 页面切换动画 功能

- 实现了在项目配置中可配置页面切换动画
- 编写 页面切换动画 功能单元测试
This commit is contained in:
XFeng
2026-01-13 19:50:40 +08:00
parent f41df4a811
commit 3bae086c32
9 changed files with 137 additions and 11 deletions

View File

@@ -2,7 +2,7 @@
<section class="app-main" :style="{ height: appMainHeight }">
<router-view>
<template #default="{ Component, route }">
<transition enter-active-class="animate__animated animate__fadeIn" mode="out-in">
<transition :name="transitionName" mode="out-in">
<keep-alive :include="cachedViews">
<component :is="currentComponent(Component, route)" :key="route.fullPath" />
</keep-alive>
@@ -25,6 +25,8 @@ import Error404 from "@/views/error/404.vue";
const { cachedViews } = toRefs(useTagsViewStore());
const settingsStore = useSettingsStore();
// 当前组件
const wrapperMap = new Map<string, Component>();
const currentComponent = (component: Component, route: RouteLocationNormalized) => {
@@ -60,12 +62,17 @@ const currentComponent = (component: Component, route: RouteLocationNormalized)
};
const appMainHeight = computed(() => {
if (useSettingsStore().showTagsView) {
if (settingsStore.showTagsView) {
return `calc(100vh - ${variables["navbar-height"]} - ${variables["tags-view-height"]})`;
} else {
return `calc(100vh - ${variables["navbar-height"]})`;
}
});
// 页面切换动画名称
const transitionName = computed(() => {
return settingsStore.pageSwitchingAnimation ?? "";
});
</script>
<style lang="scss" scoped>
@@ -74,18 +81,42 @@ const appMainHeight = computed(() => {
overflow-y: auto;
background-color: var(--el-bg-color-page);
/* 布局切换动画优化 */
&.animate__animated {
animation-duration: 0.4s;
animation-fill-mode: forwards;
/* fade */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease-in-out;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
&.animate__fadeOut {
animation-timing-function: ease-in;
/* fade-slide */
.fade-slide-leave-active,
.fade-slide-enter-active {
transition: all 0.3s;
}
.fade-slide-enter-from {
opacity: 0;
transform: translateX(-30px);
}
.fade-slide-leave-to {
opacity: 0;
transform: translateX(30px);
}
&.animate__fadeIn {
animation-timing-function: ease-out;
/* fade-scale */
.fade-scale-leave-active,
.fade-scale-enter-active {
transition: all 0.28s;
}
.fade-scale-enter-from {
opacity: 0;
transform: scale(1.2);
}
.fade-scale-leave-to {
opacity: 0;
transform: scale(0.8);
}
}
</style>

View File

@@ -49,6 +49,18 @@
<el-switch v-model="settingsStore.showWatermark" />
</div>
<div class="config-item flex-x-between">
<span class="text-xs">{{ t("settings.pageSwitchingAnimation") }}</span>
<el-select v-model="settingsStore.pageSwitchingAnimation" style="width: 150px">
<el-option
v-for="(item, key) in pageSwitchingAnimationOptions"
:key
:label="t(`settings.${item.value}`)"
:value="item.value"
/>
</el-select>
</div>
<div class="config-item flex-x-between">
<span class="text-xs">灰色模式</span>
<el-switch v-model="settingsStore.grayMode" />
@@ -159,10 +171,13 @@
import { DocumentCopy, RefreshLeft, Check } from "@element-plus/icons-vue";
const { t } = useI18n();
import { LayoutMode, SidebarColor, ThemeMode } from "@/enums";
import { LayoutMode, PageSwitchingAnimationOptions, SidebarColor, ThemeMode } from "@/enums";
import { useSettingsStore } from "@/store";
import { themeColorPresets, appConfig } from "@/settings";
// 页面切换动画选项
const pageSwitchingAnimationOptions: Record<string, OptionItem> = PageSwitchingAnimationOptions;
// 按钮图标
const copyIcon = markRaw(DocumentCopy);
const resetIcon = markRaw(RefreshLeft);