Files
SmartisanNote.Remake/src/App.vue
2025-11-03 14:48:48 +08:00

243 lines
5.5 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<!-- 网络状态指示器 -->
<div v-if="!isOnline" class="network-status">
<div class="offline-indicator">
<span class="offline-icon"></span>
<span class="offline-text">离线模式</span>
</div>
</div>
<!-- 设置页面背景列表页 -->
<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, computed, onMounted, onUnmounted } from 'vue'
import { useRoute } from 'vue-router'
import '@/common/base.css'
import { initModalService } from '@/utils/modalService'
import { addNetworkListener, removeNetworkListener, testOnline } from '@/utils/networkUtils'
// 导入页面组件
import NoteListPage from './pages/NoteListPage.vue'
import SettingsPage from './pages/SettingsPage.vue'
const route = useRoute()
const transitionName = ref('slide-left')
const modalRef = ref()
const isOnline = ref(navigator.onLine)
// 计算是否为设置页面路由
const isSettingsRoute = computed(() => {
return route.path === '/settings'
})
// 计算是否需要显示背景页面(仅在设置页面时显示)
const showBackgroundPage = computed(() => {
return route.path === '/settings'
})
// 网络状态变化回调
const handleOnline = () => {
isOnline.value = true
console.log('网络已连接')
// 可以在这里触发数据同步
}
const handleOffline = () => {
isOnline.value = false
console.log('网络已断开')
// 可以在这里显示离线提示
}
// 监听路由变化,动态设置过渡动画方向
watch(
() => route.path,
(toPath, fromPath) => {
// 特殊处理:从编辑页返回列表页的情况
if ((fromPath.startsWith('/editor') || fromPath.startsWith('/notes/')) && toPath === '/notes') {
transitionName.value = 'slide-right'
return
}
// 判断导航方向
const toDepth = toPath.split('/').length
const fromDepth = fromPath.split('/').length
// 如果是进入更深的页面(如从列表页进入编辑页),使用左滑动画
if (toDepth > fromDepth) {
transitionName.value = 'slide-left'
}
// 如果是返回上层页面(如从编辑页返回列表页),使用右滑动画
else if (toDepth < fromDepth) {
transitionName.value = 'slide-right'
}
// 同级页面切换使用默认的左滑动画
else {
transitionName.value = 'slide-left'
}
}
)
// 初始化弹框服务和网络监听
onMounted(() => {
initModalService()
addNetworkListener(handleOnline, handleOffline)
})
// 移除网络监听
onUnmounted(() => {
removeNetworkListener(handleOnline, handleOffline)
})
</script>
<style lang="less" scoped>
.app-container {
width: 100vw;
height: 100vh;
position: relative;
overflow: hidden;
background-color: #f5f5f5; // 设置默认背景色,防止闪烁
}
// 网络状态指示器
.network-status {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 10000;
display: flex;
justify-content: center;
pointer-events: none;
}
.offline-indicator {
background-color: #ff6b6b;
color: white;
padding: 8px 16px;
border-radius: 0 0 4px 4px;
font-size: 14px;
display: flex;
align-items: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
pointer-events: auto;
}
.offline-icon {
margin-right: 8px;
}
.offline-text {
font-weight: 500;
}
// 背景页面样式
.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 {
transition: all 0.3s ease;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.slide-left-enter-from {
transform: translateX(100%);
}
.slide-left-leave-to {
transform: translateX(-100%);
}
.slide-left-enter-to,
.slide-left-leave-from {
transform: translateX(0);
}
// 右滑进入(从左到右)
.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%);
}
.slide-right-leave-to {
transform: translateX(100%);
}
.slide-right-enter-to,
.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>