feat:修改主页面滚动效果
This commit is contained in:
parent
08225a7a79
commit
11df4cd8e9
@ -4,16 +4,15 @@
|
||||
:style="scrollStyle"
|
||||
scroll-x
|
||||
:show-scrollbar="false"
|
||||
:scroll-left="scrollLeft"
|
||||
:scroll-left="isIOS ? undefined : scrollLeft"
|
||||
@scroll="onScroll"
|
||||
@touchstart="onTouchStart"
|
||||
@touchend="onTouchEnd"
|
||||
@touchcancel="onTouchEnd"
|
||||
>
|
||||
<view
|
||||
class="waterfall-inner"
|
||||
:class="{ 'ios-animate': isIOS && !iosScrollPaused }"
|
||||
:style="{ width: totalWidth + 'px', height: '100%' }"
|
||||
class="waterfall-inner ios-css-animate"
|
||||
:style="innerStyle"
|
||||
>
|
||||
<view
|
||||
v-for="card in cards"
|
||||
@ -82,7 +81,8 @@ const GAP = rpx2px(16)
|
||||
const BORDER_W = rpx2px(2)
|
||||
const SCALE = 0.9
|
||||
const ROWS = 4
|
||||
const AUTO_SCROLL_SPEED = 0.3
|
||||
const AUTO_SCROLL_SPEED_ANDROID = 0.3
|
||||
const AUTO_SCROLL_SPEED_IOS = 0.015
|
||||
const AUTO_RESUME_DELAY = 1500
|
||||
const PRELOAD_THRESHOLD = rpx2px(300)
|
||||
|
||||
@ -112,79 +112,33 @@ const cafFn = (id) => {
|
||||
clearTimeout(id)
|
||||
}
|
||||
|
||||
// ========== iOS 原生自动滚动 ==========
|
||||
// iOS 使用 setInterval + scroll-left 属性实现流畅滚动
|
||||
let iosScrollTimer = null
|
||||
// ========== iOS CSS 动画自动滚动 ==========
|
||||
// iOS 使用 CSS @keyframes 动画实现流畅滚动,不再用 setInterval + scroll-left
|
||||
let iosScrollPaused = false
|
||||
let iosLastUpdateTime = 0
|
||||
let iosLastScrollValue = 0 // 上次实际设置到 scrollLeft 的值
|
||||
const IOS_SCROLL_INTERVAL = 16 // ~60fps
|
||||
const IOS_MIN_DELTA = 0.5 // 最小变化量,避免频繁更新
|
||||
|
||||
const startIOSAutoScroll = () => {
|
||||
console.log('[iOS] startIOSAutoScroll called, isIOS:', isIOS, 'isComponentMounted:', isComponentMounted)
|
||||
if (!isComponentMounted) return
|
||||
if (!isIOS) return
|
||||
stopIOSAutoScroll()
|
||||
if (!isComponentMounted || !isIOS) return
|
||||
iosScrollPaused = false
|
||||
iosLastUpdateTime = 0
|
||||
iosLastScrollValue = autoScrollPos
|
||||
|
||||
iosScrollTimer = setInterval(() => {
|
||||
if (!isComponentMounted || iosScrollPaused) return
|
||||
|
||||
const now = Date.now()
|
||||
// 节流:每 16ms 更新一次
|
||||
if (now - iosLastUpdateTime >= IOS_SCROLL_INTERVAL) {
|
||||
iosLastUpdateTime = now
|
||||
const newPos = autoScrollPos + AUTO_SCROLL_SPEED
|
||||
|
||||
// 只在变化足够大时更新,减少抖动
|
||||
if (Math.abs(newPos - iosLastScrollValue) >= IOS_MIN_DELTA) {
|
||||
autoScrollPos = newPos
|
||||
iosLastScrollValue = newPos
|
||||
scrollLeft.value = newPos
|
||||
} else {
|
||||
autoScrollPos = newPos // 保持 autoScrollPos 增长但不同步到 scrollLeft
|
||||
}
|
||||
|
||||
// 预加载
|
||||
const remainingScroll = totalWidth.value - autoScrollPos - props.screenWidth
|
||||
if (remainingScroll < Math.max(totalWidth.value / 2, props.screenWidth)) {
|
||||
if (!isLoadingMore && !appendFailed && !isInitialLoading && props.useMockData) {
|
||||
appendMore()
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 16)
|
||||
}
|
||||
|
||||
const stopIOSAutoScroll = () => {
|
||||
console.log('[iOS] stopIOSAutoScroll')
|
||||
clearInterval(iosScrollTimer)
|
||||
iosScrollTimer = null
|
||||
iosScrollPaused = true
|
||||
}
|
||||
|
||||
const pauseIOSAutoScroll = () => {
|
||||
console.log('[iOS] pauseIOSAutoScroll')
|
||||
iosScrollPaused = true
|
||||
}
|
||||
|
||||
const resumeIOSAutoScroll = () => {
|
||||
console.log('[iOS] resumeIOSAutoScroll')
|
||||
iosScrollPaused = false
|
||||
iosLastUpdateTime = 0
|
||||
autoScrollPos = currentScrollLeft
|
||||
iosLastScrollValue = currentScrollLeft
|
||||
}
|
||||
let rafId = null
|
||||
let userInteracting = false
|
||||
let resumeTimer = null
|
||||
let appendTimer = null // 防抖定时器
|
||||
let autoScrollPos = 0 // 自动滚动目标位置
|
||||
let momentumTimer = null // iOS 惯性滚动检测定时器
|
||||
let scrollUpdateTimer = null // 定期同步 scrollLeft 的定时器
|
||||
let iosAutoScrollTimer = null // iOS 原生滚动定时器(检测惯性结束)
|
||||
let momentumTimer = null // iOS/Android 惯性滚动检测定时器
|
||||
let scrollUpdateTimer = null // 定期同步 scrollLeft 的定时器(仅 Android)
|
||||
|
||||
const startAutoScroll = () => {
|
||||
if (!isComponentMounted || isIOS) return
|
||||
@ -199,7 +153,7 @@ const startAutoScroll = () => {
|
||||
clearInterval(scrollUpdateTimer)
|
||||
scrollUpdateTimer = setInterval(() => {
|
||||
if (!isComponentMounted || userInteracting || isLoadingMore) return
|
||||
autoScrollPos += AUTO_SCROLL_SPEED
|
||||
autoScrollPos += AUTO_SCROLL_SPEED_ANDROID
|
||||
scrollLeft.value = autoScrollPos
|
||||
|
||||
// 预加载
|
||||
@ -225,8 +179,6 @@ const stopAutoScroll = () => {
|
||||
resumeTimer = null
|
||||
clearTimeout(momentumTimer)
|
||||
momentumTimer = null
|
||||
clearTimeout(iosAutoScrollTimer)
|
||||
iosAutoScrollTimer = null
|
||||
userInteracting = false
|
||||
isLoadingMore = false
|
||||
}
|
||||
@ -340,6 +292,23 @@ const scrollStyle = computed(() => ({
|
||||
// overflow: 'visible',
|
||||
}))
|
||||
|
||||
// iOS CSS 动画内联样式
|
||||
const innerStyle = computed(() => {
|
||||
if (!isIOS) {
|
||||
return { width: totalWidth.value + 'px', height: '100%' }
|
||||
}
|
||||
const scrollDist = totalWidth.value
|
||||
// 速度:px/ms,iOS 使用 AUTO_SCROLL_SPEED_IOS
|
||||
const duration = scrollDist / AUTO_SCROLL_SPEED_IOS
|
||||
return {
|
||||
width: scrollDist + 'px',
|
||||
height: '100%',
|
||||
'--scroll-dist': -scrollDist + 'px',
|
||||
'--anim-duration': duration + 'ms',
|
||||
'--play-state': iosScrollPaused ? 'paused' : 'running',
|
||||
}
|
||||
})
|
||||
|
||||
// ========== 布局引擎 ==========
|
||||
// 核心思路:按列放置,每列的卡片 span 之和 = ROWS,保证零空缺
|
||||
// 同一列内所有卡片宽度统一 = 整列宽(span=ROWS 对应的宽),高度各自按 span 计算
|
||||
@ -981,11 +950,14 @@ watch(() => props.category, (newCategory) => {
|
||||
top: 32rpx;
|
||||
}
|
||||
|
||||
.ios-animate {
|
||||
will-change: transform;
|
||||
transform: translate3d(0, 0, 0);
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scroll-behavior: auto;
|
||||
.ios-css-animate {
|
||||
animation: iosAutoScroll var(--anim-duration) linear infinite;
|
||||
animation-play-state: var(--play-state, running);
|
||||
}
|
||||
|
||||
@keyframes iosAutoScroll {
|
||||
from { transform: translateX(0); }
|
||||
to { transform: translateX(var(--scroll-dist)); }
|
||||
}
|
||||
|
||||
.wf-card {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user