"优化页面切换动画效果"

This commit is contained in:
yuantao
2025-10-23 17:10:34 +08:00
parent c1217185f3
commit 0c4e92a4b8
4 changed files with 341 additions and 10 deletions

247
package-lock.json generated
View File

@@ -14,6 +14,8 @@
"@capacitor/core": "^5.7.2",
"@capacitor/ios": "^5.7.2",
"@ionic/vue": "^8.7.6",
"@motionone/vue": "^10.16.4",
"@oku-ui/motion": "^0.4.3",
"@vue/cli-service": "^5.0.9",
"@vue/compiler-sfc": "^3.5.22",
"basic-ftp": "^5.0.5",
@@ -2125,6 +2127,63 @@
"node": ">=12"
}
},
"node_modules/@floating-ui/core": {
"version": "1.7.3",
"resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.3.tgz",
"integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==",
"dependencies": {
"@floating-ui/utils": "^0.2.10"
}
},
"node_modules/@floating-ui/dom": {
"version": "1.7.4",
"resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.7.4.tgz",
"integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==",
"dependencies": {
"@floating-ui/core": "^1.7.3",
"@floating-ui/utils": "^0.2.10"
}
},
"node_modules/@floating-ui/utils": {
"version": "0.2.10",
"resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.10.tgz",
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="
},
"node_modules/@floating-ui/vue": {
"version": "1.1.9",
"resolved": "https://registry.npmmirror.com/@floating-ui/vue/-/vue-1.1.9.tgz",
"integrity": "sha512-BfNqNW6KA83Nexspgb9DZuz578R7HT8MZw1CfK9I6Ah4QReNWEJsXWHN+SdmOVLNGmTPDi+fDT535Df5PzMLbQ==",
"dependencies": {
"@floating-ui/dom": "^1.7.4",
"@floating-ui/utils": "^0.2.10",
"vue-demi": ">=0.13.0"
}
},
"node_modules/@floating-ui/vue/node_modules/vue-demi": {
"version": "0.14.10",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.10.tgz",
"integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
"hasInstallScript": true,
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@hapi/hoek": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
@@ -2465,6 +2524,74 @@
"integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==",
"license": "MIT"
},
"node_modules/@motionone/animation": {
"version": "10.18.0",
"resolved": "https://registry.npmmirror.com/@motionone/animation/-/animation-10.18.0.tgz",
"integrity": "sha512-9z2p5GFGCm0gBsZbi8rVMOAJCtw1WqBTIPw3ozk06gDvZInBPIsQcHgYogEJ4yuHJ+akuW8g1SEIOpTOvYs8hw==",
"dependencies": {
"@motionone/easing": "^10.18.0",
"@motionone/types": "^10.17.1",
"@motionone/utils": "^10.18.0",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/dom": {
"version": "10.18.0",
"resolved": "https://registry.npmmirror.com/@motionone/dom/-/dom-10.18.0.tgz",
"integrity": "sha512-bKLP7E0eyO4B2UaHBBN55tnppwRnaE3KFfh3Ps9HhnAkar3Cb69kUCJY9as8LrccVYKgHA+JY5dOQqJLOPhF5A==",
"dependencies": {
"@motionone/animation": "^10.18.0",
"@motionone/generators": "^10.18.0",
"@motionone/types": "^10.17.1",
"@motionone/utils": "^10.18.0",
"hey-listen": "^1.0.8",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/easing": {
"version": "10.18.0",
"resolved": "https://registry.npmmirror.com/@motionone/easing/-/easing-10.18.0.tgz",
"integrity": "sha512-VcjByo7XpdLS4o9T8t99JtgxkdMcNWD3yHU/n6CLEz3bkmKDRZyYQ/wmSf6daum8ZXqfUAgFeCZSpJZIMxaCzg==",
"dependencies": {
"@motionone/utils": "^10.18.0",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/generators": {
"version": "10.18.0",
"resolved": "https://registry.npmmirror.com/@motionone/generators/-/generators-10.18.0.tgz",
"integrity": "sha512-+qfkC2DtkDj4tHPu+AFKVfR/C30O1vYdvsGYaR13W/1cczPrrcjdvYCj0VLFuRMN+lP1xvpNZHCRNM4fBzn1jg==",
"dependencies": {
"@motionone/types": "^10.17.1",
"@motionone/utils": "^10.18.0",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/types": {
"version": "10.17.1",
"resolved": "https://registry.npmmirror.com/@motionone/types/-/types-10.17.1.tgz",
"integrity": "sha512-KaC4kgiODDz8hswCrS0btrVrzyU2CSQKO7Ps90ibBVSQmjkrt2teqta6/sOG59v7+dPnKMAg13jyqtMKV2yJ7A=="
},
"node_modules/@motionone/utils": {
"version": "10.18.0",
"resolved": "https://registry.npmmirror.com/@motionone/utils/-/utils-10.18.0.tgz",
"integrity": "sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw==",
"dependencies": {
"@motionone/types": "^10.17.1",
"hey-listen": "^1.0.8",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/vue": {
"version": "10.16.4",
"resolved": "https://registry.npmmirror.com/@motionone/vue/-/vue-10.16.4.tgz",
"integrity": "sha512-z10PF9JV6SbjFq+/rYabM+8CVlMokgl8RFGvieSGNTmrkQanfHn+15XBrhG3BgUfvmTeSeyShfOHpG0i9zEdcg==",
"deprecated": "Motion One for Vue is deprecated. Use Oku Motion instead https://oku-ui.com/motion",
"dependencies": {
"@motionone/dom": "^10.16.4",
"tslib": "^2.3.1"
}
},
"node_modules/@node-ipc/js-queue": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@node-ipc/js-queue/-/js-queue-2.0.3.tgz",
@@ -2512,6 +2639,41 @@
"node": ">= 8"
}
},
"node_modules/@oku-ui/motion": {
"version": "0.4.3",
"resolved": "https://registry.npmmirror.com/@oku-ui/motion/-/motion-0.4.3.tgz",
"integrity": "sha512-Z4fd1BaxfwhEImmsYp5szZ3YNATG64l6cOn8Nia3KaUwYNPhIbfM2wME5cnEFe3JLh1kBaANsJgcJZT1ZSI+mw==",
"dependencies": {
"@oku-ui/primitives": "^0.7.5",
"defu": "^6.1.4",
"framer-motion": "^11.11.17",
"hey-listen": "^1.0.8",
"motion": "^11.11.17"
},
"funding": {
"url": "https://github.com/sponsors/productdevbook"
},
"peerDependencies": {
"@vue/shared": "^3.4.31"
}
},
"node_modules/@oku-ui/primitives": {
"version": "0.7.8",
"resolved": "https://registry.npmmirror.com/@oku-ui/primitives/-/primitives-0.7.8.tgz",
"integrity": "sha512-Q0QcyZ23jzx84p6I5PK3BS1Szs9bmSTD4OcOjRq5pqw8W9YBWIXHiDpShvW3B2pKofjNn0RtNund5EZwF1GCVw==",
"dependencies": {
"@floating-ui/dom": "^1.6.12",
"@floating-ui/utils": "^0.2.8",
"@floating-ui/vue": "^1.1.5",
"aria-hidden": "^1.2.4"
},
"funding": {
"url": "https://github.com/sponsors/productdevbook"
},
"peerDependencies": {
"vue": ">= 3.5.0"
}
},
"node_modules/@polka/url": {
"version": "1.0.0-next.29",
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
@@ -4149,6 +4311,17 @@
],
"license": "MIT"
},
"node_modules/aria-hidden": {
"version": "1.2.6",
"resolved": "https://registry.npmmirror.com/aria-hidden/-/aria-hidden-1.2.6.tgz",
"integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
"dependencies": {
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/array-buffer-byte-length": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz",
@@ -5767,6 +5940,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/defu": {
"version": "6.1.4",
"resolved": "https://registry.npmmirror.com/defu/-/defu-6.1.4.tgz",
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -6711,6 +6889,32 @@
"url": "https://github.com/sponsors/rawify"
}
},
"node_modules/framer-motion": {
"version": "11.18.2",
"resolved": "https://registry.npmmirror.com/framer-motion/-/framer-motion-11.18.2.tgz",
"integrity": "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==",
"dependencies": {
"motion-dom": "^11.18.1",
"motion-utils": "^11.18.1",
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -7137,6 +7341,11 @@
"he": "bin/he"
}
},
"node_modules/hey-listen": {
"version": "1.0.8",
"resolved": "https://registry.npmmirror.com/hey-listen/-/hey-listen-1.0.8.tgz",
"integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
},
"node_modules/highlight.js": {
"version": "10.7.3",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
@@ -8950,6 +9159,44 @@
"node": "*"
}
},
"node_modules/motion": {
"version": "11.18.2",
"resolved": "https://registry.npmmirror.com/motion/-/motion-11.18.2.tgz",
"integrity": "sha512-JLjvFDuFr42NFtcVoMAyC2sEjnpA8xpy6qWPyzQvCloznAyQ8FIXioxWfHiLtgYhoVpfUqSWpn1h9++skj9+Wg==",
"dependencies": {
"framer-motion": "^11.18.2",
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/motion-dom": {
"version": "11.18.1",
"resolved": "https://registry.npmmirror.com/motion-dom/-/motion-dom-11.18.1.tgz",
"integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==",
"dependencies": {
"motion-utils": "^11.18.1"
}
},
"node_modules/motion-utils": {
"version": "11.18.1",
"resolved": "https://registry.npmmirror.com/motion-utils/-/motion-utils-11.18.1.tgz",
"integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA=="
},
"node_modules/mrmime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",

View File

@@ -1,21 +1,49 @@
<template>
<div class="app-container">
<router-view v-slot="{ Component, route }">
<transition :name="transitionName">
<component :is="Component" :key="route.path" />
</transition>
</router-view>
<!-- 设置页面背景列表页 -->
<NoteListPage v-show="showBackgroundPage" class="background-page" />
<!-- 普通页面过渡效果不包括设置页面 -->
<template v-if="!isSettingsRoute">
<router-view v-slot="{ Component, route }">
<transition :name="transitionName">
<component :is="Component" :key="route.path" />
</transition>
</router-view>
</template>
<!-- 设置页面 -->
<transition
name="settings-slide"
v-show="isSettingsRoute"
appear>
<SettingsPage class="setting-page" />
</transition>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
import { ref, watch, computed } from 'vue'
import { useRoute } from 'vue-router'
import '@/common/base.css'
// 导入页面组件
import NoteListPage from './pages/NoteListPage.vue'
import SettingsPage from './pages/SettingsPage.vue'
const route = useRoute()
const transitionName = ref('slide-left')
// 计算是否为设置页面路由
const isSettingsRoute = computed(() => {
return route.path === '/settings'
})
// 计算是否需要显示背景页面(仅在设置页面时显示)
const showBackgroundPage = computed(() => {
return route.path === '/settings'
})
// 监听路由变化,动态设置过渡动画方向
watch(
() => route.path,
@@ -44,6 +72,8 @@ watch(
}
}
)
// 无额外处理函数
</script>
<style lang="less" scoped>
@@ -55,11 +85,28 @@ watch(
background-color: #f5f5f5; // 设置默认背景色,防止闪烁
}
// 背景页面样式
.background-page {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 1;
}
.setting-page {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 2;
}
// 左滑进入(从右到左)
.slide-left-enter-active,
.slide-left-leave-active,
.slide-right-enter-active,
.slide-right-leave-active {
.slide-left-leave-active {
transition: all 0.3s ease;
position: absolute;
width: 100%;
@@ -82,6 +129,16 @@ watch(
}
// 右滑进入(从左到右)
.slide-right-enter-active,
.slide-right-leave-active {
transition: all 0.3s ease;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.slide-right-enter-from {
transform: translateX(-100%);
}
@@ -94,4 +151,29 @@ watch(
.slide-right-leave-from {
transform: translateX(0);
}
// 设置页面滑入滑出效果
.settings-slide-enter-active,
.settings-slide-leave-active {
transition: transform 0.3s ease;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 10;
}
.settings-slide-enter-from {
transform: translateY(100%);
}
.settings-slide-leave-to {
transform: translateY(100%);
}
.settings-slide-enter-to,
.settings-slide-leave-from {
transform: translateY(0);
}
</style>

View File

@@ -29,6 +29,7 @@ import { useAppStore } from '../stores/useAppStore'
import Header from '../components/Header.vue'
import RichTextEditor from '../components/RichTextEditor.vue'
import { formatNoteEditorDate } from '../utils/dateUtils'
import { IonPage } from '@ionic/vue'
const props = defineProps({
id: {

View File

@@ -40,6 +40,7 @@ import { useAppStore } from '../stores/useAppStore'
import Header from '../components/Header.vue'
import SettingGroup from '../components/SettingGroup.vue'
import SwitchButton from '../components/SwitchButton.vue'
import { IonPage } from '@ionic/vue'
const store = useAppStore()
const router = useRouter()
@@ -52,7 +53,7 @@ onMounted(() => {
// 切换云同步设置
// 调用store中的方法更新云同步状态
const toggleCloudSync = (value) => {
const toggleCloudSync = value => {
store.toggleCloudSync()
}