大图查看页面优化:新增图片切换淡入淡出动画,并通过预加载提升切换速度

This commit is contained in:
2026-01-29 16:15:59 +08:00
parent 5e3defc63d
commit c32cb8da3f

View File

@@ -1,18 +1,19 @@
<template>
<div class="fixed inset-0 bg-black z-50 overflow-hidden">
<!-- 加载状态 -->
<div v-if="loading" class="absolute inset-0 flex items-center justify-center">
<!-- 加载状态动画过渡中不显示 -->
<div v-if="loading && !imageTransitioning" class="absolute inset-0 flex items-center justify-center">
<div class="w-16 h-16 border-4 border-white/20 border-t-white rounded-full animate-spin"></div>
</div>
<!-- 主要内容 -->
<div v-else-if="image" class="relative h-full w-full">
<div v-else-if="image || imageTransitioning" class="relative h-full w-full">
<!-- 全屏图片 -->
<div class="absolute inset-0 flex items-center justify-center">
<img
:src="getFullImageUrl()"
:alt="image.title || 'Bing Image'"
class="max-w-full max-h-full object-contain"
class="max-w-full max-h-full object-contain transition-opacity duration-500 ease-in-out"
:style="{ opacity: imageOpacity }"
/>
</div>
@@ -204,6 +205,8 @@ const currentDate = ref(route.params.date as string)
const showInfo = ref(true)
const showCalendar = ref(getInitialCalendarState())
const navigating = ref(false)
const imageOpacity = ref(1)
const imageTransitioning = ref(false)
// 前后日期可用性
const hasPreviousDay = ref(true)
@@ -415,6 +418,63 @@ const getFullImageUrl = () => {
return bingPaperApi.getImageUrlByDate(currentDate.value, 'UHD', 'jpg')
}
// 预加载图片
const preloadImage = (url: string): Promise<void> => {
return new Promise((resolve, reject) => {
const img = new Image()
img.onload = () => resolve()
img.onerror = () => reject(new Error('Failed to load image'))
img.src = url
})
}
// 预加载图片和数据
const preloadImageAndData = async (date: string): Promise<void> => {
try {
// 并行预加载图片和数据
const imageUrl = bingPaperApi.getImageUrlByDate(date, 'UHD', 'jpg')
await Promise.all([
preloadImage(imageUrl),
bingPaperApi.getImageMetaByDate(date)
])
} catch (error) {
console.warn('Failed to preload image or data:', error)
// 即使预加载失败也继续
}
}
// 切换日期并带动画
const switchToDate = async (newDate: string) => {
if (imageTransitioning.value) return
imageTransitioning.value = true
// 1. 淡出当前图片的同时预加载新图片和数据
imageOpacity.value = 0
const preloadPromise = preloadImageAndData(newDate)
// 2. 等待淡出动画完成500ms
await Promise.all([
new Promise(resolve => setTimeout(resolve, 500)),
preloadPromise
])
// 3. 更新日期(此时图片和数据已经预加载完成)
currentDate.value = newDate
router.replace(`/image/${newDate}`)
// 4. 等待一个微任务,确保 DOM 更新
await new Promise(resolve => setTimeout(resolve, 50))
// 5. 淡入新图片
imageOpacity.value = 1
// 6. 等待淡入完成
await new Promise(resolve => setTimeout(resolve, 500))
imageTransitioning.value = false
}
// copyrightlink 现在是完整的 URL无需额外处理
// 返回首页
@@ -423,37 +483,31 @@ const goBack = () => {
}
// 前一天
const previousDay = () => {
if (navigating.value || !hasPreviousDay.value) return
const previousDay = async () => {
if (navigating.value || !hasPreviousDay.value || imageTransitioning.value) return
navigating.value = true
const date = new Date(currentDate.value)
date.setDate(date.getDate() - 1)
const newDate = date.toISOString().split('T')[0]
currentDate.value = newDate
router.replace(`/image/${newDate}`)
await switchToDate(newDate)
setTimeout(() => {
navigating.value = false
}, 500)
navigating.value = false
}
// 后一天
const nextDay = () => {
if (navigating.value || !hasNextDay.value) return
const nextDay = async () => {
if (navigating.value || !hasNextDay.value || imageTransitioning.value) return
navigating.value = true
const date = new Date(currentDate.value)
date.setDate(date.getDate() + 1)
const newDate = date.toISOString().split('T')[0]
currentDate.value = newDate
router.replace(`/image/${newDate}`)
await switchToDate(newDate)
setTimeout(() => {
navigating.value = false
}, 500)
navigating.value = false
}
// 切换日历状态watch会自动保存