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
密码R251Y>Y8inL_BM=W
https://testflight.apple.com/join/znR5FGdG
# TopFans

View File

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

View File

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