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)
}
}