Compare commits

...

2 Commits

Author SHA1 Message Date
zerosaturation
e81ef0a375 fix:修改瀑布流ios的抖动现象 2026-05-13 13:03:45 +08:00
zerosaturation
36e36b07c2 feat: 修改瀑布流ios抖动现象 2026-05-12 22:56:20 +08:00
3 changed files with 45 additions and 29 deletions

View File

@ -1,3 +1 @@
# TopFans # TopFans
密码R251Y>Y8inL_BM=W
https://testflight.apple.com/join/znR5FGdG

View File

@ -5,12 +5,14 @@
scroll-x scroll-x
:show-scrollbar="false" :show-scrollbar="false"
:scroll-left="isIOS ? undefined : scrollLeft" :scroll-left="isIOS ? undefined : scrollLeft"
:bounce="false"
@scroll="onScroll" @scroll="onScroll"
@touchstart="onTouchStart" @touchstart="onTouchStart"
@touchend="onTouchEnd" @touchend="onTouchEnd"
@touchcancel="onTouchEnd" @touchcancel="onTouchEnd"
> >
<view <view
ref="waterfallInnerRef"
class="waterfall-inner ios-css-animate" class="waterfall-inner ios-css-animate"
:style="innerStyle" :style="innerStyle"
> >
@ -114,23 +116,23 @@ const cafFn = (id) => {
// ========== iOS CSS ========== // ========== iOS CSS ==========
// iOS 使 CSS @keyframes setInterval + scroll-left // iOS 使 CSS @keyframes setInterval + scroll-left
let iosScrollPaused = false const iosScrollPaused = ref(true)
const startIOSAutoScroll = () => { const startIOSAutoScroll = () => {
if (!isComponentMounted || !isIOS) return if (!isComponentMounted || !isIOS) return
iosScrollPaused = false iosScrollPaused.value = false
} }
const stopIOSAutoScroll = () => { const stopIOSAutoScroll = () => {
iosScrollPaused = true iosScrollPaused.value = true
} }
const pauseIOSAutoScroll = () => { const pauseIOSAutoScroll = () => {
iosScrollPaused = true iosScrollPaused.value = true
} }
const resumeIOSAutoScroll = () => { const resumeIOSAutoScroll = () => {
iosScrollPaused = false iosScrollPaused.value = false
} }
let rafId = null let rafId = null
let userInteracting = false let userInteracting = false
@ -223,8 +225,8 @@ let isManualScrolling = false // 是否正在手动滚动
const onTouchStart = (e) => { const onTouchStart = (e) => {
if (isIOS) { if (isIOS) {
// iOS // iOS CSS
stopIOSAutoScroll() pauseIOSAutoScroll()
isManualScrolling = true isManualScrolling = true
clearTimeout(momentumTimer) clearTimeout(momentumTimer)
} else { } else {
@ -243,13 +245,12 @@ const onTouchEnd = () => {
const tick = () => { const tick = () => {
momentumTimer = setTimeout(() => { momentumTimer = setTimeout(() => {
if (Math.abs(currentScrollLeft - lastTouchEndPos) < 2) { if (Math.abs(currentScrollLeft - lastTouchEndPos) < 2) {
// 300ms // 500ms
clearTimeout(momentumTimer) clearTimeout(momentumTimer)
momentumTimer = setTimeout(() => { momentumTimer = setTimeout(() => {
isManualScrolling = false isManualScrolling = false
autoScrollPos = currentScrollLeft resumeIOSAutoScroll()
startIOSAutoScroll() }, 1500)
}, 300)
} else { } else {
// //
lastTouchEndPos = currentScrollLeft lastTouchEndPos = currentScrollLeft
@ -305,7 +306,9 @@ const innerStyle = computed(() => {
height: '100%', height: '100%',
'--scroll-dist': -scrollDist + 'px', '--scroll-dist': -scrollDist + 'px',
'--anim-duration': duration + 'ms', '--anim-duration': duration + 'ms',
'--play-state': iosScrollPaused ? 'paused' : 'running', '--play-state': iosScrollPaused.value ? 'paused' : 'running',
// animation-play-state
animationPlayState: iosScrollPaused.value ? 'paused' : 'running',
} }
}) })
@ -537,7 +540,7 @@ const batchGetPresignedUrls = async (urls) => {
} }
const loadUsers = async () => { const loadUsers = async () => {
if (!isComponentMounted) return if (!isComponentMounted) return Promise.resolve()
// //
mockDataOffset = 0 mockDataOffset = 0
@ -758,13 +761,11 @@ onMounted(() => {
// iOS 使 // iOS 使
const sysInfo = uni.getSystemInfoSync() const sysInfo = uni.getSystemInfoSync()
isIOS = sysInfo.platform === 'ios' isIOS = sysInfo.platform === 'ios'
console.log('[WaterfallGrid] onMounted, platform:', sysInfo.platform, 'isIOS:', isIOS)
const containerH = props.screenHeight - props.bannerBottom const containerH = props.screenHeight - props.bannerBottom
layout = new WaterfallLayout(containerH, props.category) layout = new WaterfallLayout(containerH, props.category)
loadUsers().then(() => { loadUsers().then(() => {
isInitialLoading = false isInitialLoading = false
nextTick(() => { nextTick(() => {
console.log('[WaterfallGrid] loadUsers done, calling auto scroll, isIOS:', isIOS)
if (isIOS) { if (isIOS) {
startIOSAutoScroll() startIOSAutoScroll()
} else { } else {
@ -925,22 +926,32 @@ watch(() => props.category, (newCategory) => {
rafId = null rafId = null
} }
loadUsers().then(() => { // key
nextTick(() => { //
if (isIOS) { setTimeout(() => {
startIOSAutoScroll() loadUsersAndStartScroll()
} else { }, 0)
startAutoScroll()
}
})
})
} }
}) })
const loadUsersAndStartScroll = () => {
loadUsers().then(() => {
nextTick(() => {
if (isIOS) {
// iOS
iosScrollPaused.value = false
} else {
startAutoScroll()
}
})
})
}
</script> </script>
<style scoped> <style scoped>
.waterfall-scroll { .waterfall-scroll {
white-space: nowrap; white-space: nowrap;
overflow: hidden;
} }
.waterfall-inner { .waterfall-inner {
@ -952,7 +963,6 @@ watch(() => props.category, (newCategory) => {
.ios-css-animate { .ios-css-animate {
animation: iosAutoScroll var(--anim-duration) linear infinite; animation: iosAutoScroll var(--anim-duration) linear infinite;
animation-play-state: var(--play-state, running);
} }
@keyframes iosAutoScroll { @keyframes iosAutoScroll {

View File

@ -5,6 +5,7 @@
<!-- 横向瀑布流卡片层内部自带横向滚动 --> <!-- 横向瀑布流卡片层内部自带横向滚动 -->
<WaterfallGrid <WaterfallGrid
:key="waterfallKey"
:screenWidth="screenWidth" :screenWidth="screenWidth"
:screenHeight="screenHeight" :screenHeight="screenHeight"
:bannerBottom="bannerBottomPx" :bannerBottom="bannerBottomPx"
@ -59,7 +60,7 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue' import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
import { onLoad, onShow, onHide } from '@dcloudio/uni-app' import { onLoad, onShow, onHide } from '@dcloudio/uni-app'
import { useStore } from 'vuex' import { useStore } from 'vuex'
import Header from '../components/Header.vue' import Header from '../components/Header.vue'
@ -80,10 +81,17 @@ const currentStarId = ref(uni.getStorageSync('star_id') || null)
// ========== UI State ========== // ========== UI State ==========
const activeContentTab = ref('random') const activeContentTab = ref('random')
const waterfallKey = ref(0) // WaterfallGrid
const navExpanded = ref(false) const navExpanded = ref(false)
const showRankingModal = ref(false) const showRankingModal = ref(false)
const isActive = ref(true) const isActive = ref(true)
// ========== Watch activeContentTab ==========
watch(activeContentTab, () => {
// WaterfallGridiOS CSS
waterfallKey.value++
})
// ========== Screen Info ========== // ========== Screen Info ==========
const screenWidth = ref(375) const screenWidth = ref(375)
const screenHeight = ref(812) const screenHeight = ref(812)