diff --git a/vite-tailwindcss/src/components/PhotoGallery.vue b/vite-tailwindcss/src/components/PhotoGallery.vue index 4755317..c9ab4f3 100644 --- a/vite-tailwindcss/src/components/PhotoGallery.vue +++ b/vite-tailwindcss/src/components/PhotoGallery.vue @@ -38,9 +38,9 @@
-
- +
+
@@ -144,6 +144,26 @@ function polaroidTransform(i) { .gallery-subtitle { font-family: var(--font-display); } .gallery-desc { font-family: var(--font-kai); } +.nine-grid-reveal.reveal { + transform: translate3d(0, 12px, 0); + transition: + opacity 420ms ease-out, + transform 420ms cubic-bezier(0.22, 1, 0.36, 1); + will-change: opacity, transform; +} +.nine-grid-reveal.reveal--in { + transform: translate3d(0, 0, 0); +} +.nine-grid-img { + width: 100%; + height: 100%; + object-fit: cover; + transform: translateZ(0); + transition: transform 420ms ease-out; + backface-visibility: hidden; +} +.nine-grid-img:hover { transform: translateZ(0) scale(1.03); } + /* 错落双图:高度随视口缩放并封顶,保证标题+图片总高始终落在页高预算内 */ .overlap-wrap { height: clamp(320px, 54vh, 460px); } diff --git a/vite-tailwindcss/src/views/index/index.vue b/vite-tailwindcss/src/views/index/index.vue index 9e140a5..5fb7aec 100644 --- a/vite-tailwindcss/src/views/index/index.vue +++ b/vite-tailwindcss/src/views/index/index.vue @@ -324,6 +324,7 @@ const rsvpForm = reactive({ name: '', guest_count: '1', wishes: '' }) const rsvpOptions = [ { value: '1', label: '1 人出席' }, { value: '2', label: '2 人出席' }, { value: '3', label: '3 人及以上' }, { value: '0', label: '遗憾缺席' } ] let rafId = null, snapTimer = null, pauseTimer = null, introTimer = null, freeTimer = null, animId = null, scrollStartTimer = null, bottomReturnTimer = null +let freeScrollLastTs = 0 const BOTTOM_RETURN_DELAY = 30000 // 后台可配置的滚动参数(带默认值兜底,防止脏数据) @@ -464,24 +465,30 @@ const startAutoScroll = () => { clearTimeout(scrollStartTimer) clearInterval(snapTimer) clearInterval(freeTimer) + cancelAnimationFrame(rafId) if (data.value.scrollMode === 'snap') { if (isAutoScroll.value && !isInteracting.value && !isDrawerOpen.value) goNextSection() snapTimer = setInterval(() => { if (isAutoScroll.value && !isInteracting.value && !isDrawerOpen.value) goNextSection() }, 4500) } else { - // 自由滚动:setInterval 按后台配置的间隔匀速推进(间隔越小越快) - freeTimer = setInterval(() => { + // 自由滚动:按浏览器帧率匀速推进,速度仍由后台间隔控制(间隔越小越快) + freeScrollLastTs = 0 + const tickFreeScroll = (now) => { + const dt = freeScrollLastTs ? Math.min(34, now - freeScrollLastTs) : 16.7 + freeScrollLastTs = now const el = scrollContainerRef.value if (el && isAutoScroll.value && !isInteracting.value && !isDrawerOpen.value) { if (isAtBottom(el)) { scheduleBottomReturn() - return + } else { + el.scrollTop += dt * (1.2 / freeInterval.value) + if (isAtBottom(el)) scheduleBottomReturn() } - el.scrollTop += 1.2 - if (isAtBottom(el)) scheduleBottomReturn() } - }, freeInterval.value) + rafId = requestAnimationFrame(tickFreeScroll) + } + rafId = requestAnimationFrame(tickFreeScroll) } }