Compare commits
No commits in common. "e81ef0a3758037d7c0973abb6e0f561d2ca6056f" and "6a6233f2de7bf7ccd26eb3c4142f95e705307101" have entirely different histories.
e81ef0a375
...
6a6233f2de
@ -1 +1,3 @@
|
|||||||
# TopFans
|
# TopFans
|
||||||
|
密码:R251Y>Y8inL_BM=W
|
||||||
|
https://testflight.apple.com/join/znR5FGdG
|
||||||
@ -5,14 +5,12 @@
|
|||||||
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"
|
||||||
>
|
>
|
||||||
@ -116,23 +114,23 @@ const cafFn = (id) => {
|
|||||||
|
|
||||||
// ========== iOS CSS 动画自动滚动 ==========
|
// ========== iOS CSS 动画自动滚动 ==========
|
||||||
// iOS 使用 CSS @keyframes 动画实现流畅滚动,不再用 setInterval + scroll-left
|
// iOS 使用 CSS @keyframes 动画实现流畅滚动,不再用 setInterval + scroll-left
|
||||||
const iosScrollPaused = ref(true)
|
let iosScrollPaused = false
|
||||||
|
|
||||||
const startIOSAutoScroll = () => {
|
const startIOSAutoScroll = () => {
|
||||||
if (!isComponentMounted || !isIOS) return
|
if (!isComponentMounted || !isIOS) return
|
||||||
iosScrollPaused.value = false
|
iosScrollPaused = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const stopIOSAutoScroll = () => {
|
const stopIOSAutoScroll = () => {
|
||||||
iosScrollPaused.value = true
|
iosScrollPaused = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const pauseIOSAutoScroll = () => {
|
const pauseIOSAutoScroll = () => {
|
||||||
iosScrollPaused.value = true
|
iosScrollPaused = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const resumeIOSAutoScroll = () => {
|
const resumeIOSAutoScroll = () => {
|
||||||
iosScrollPaused.value = false
|
iosScrollPaused = false
|
||||||
}
|
}
|
||||||
let rafId = null
|
let rafId = null
|
||||||
let userInteracting = false
|
let userInteracting = false
|
||||||
@ -225,8 +223,8 @@ let isManualScrolling = false // 是否正在手动滚动
|
|||||||
|
|
||||||
const onTouchStart = (e) => {
|
const onTouchStart = (e) => {
|
||||||
if (isIOS) {
|
if (isIOS) {
|
||||||
// iOS 设备:暂停 CSS 动画,让用户可以自由滚动
|
// iOS 设备:完全停止自动滚动
|
||||||
pauseIOSAutoScroll()
|
stopIOSAutoScroll()
|
||||||
isManualScrolling = true
|
isManualScrolling = true
|
||||||
clearTimeout(momentumTimer)
|
clearTimeout(momentumTimer)
|
||||||
} else {
|
} else {
|
||||||
@ -245,12 +243,13 @@ const onTouchEnd = () => {
|
|||||||
const tick = () => {
|
const tick = () => {
|
||||||
momentumTimer = setTimeout(() => {
|
momentumTimer = setTimeout(() => {
|
||||||
if (Math.abs(currentScrollLeft - lastTouchEndPos) < 2) {
|
if (Math.abs(currentScrollLeft - lastTouchEndPos) < 2) {
|
||||||
// 惯性真正结束,等 500ms 确保惯性完全停止后再恢复
|
// 惯性真正结束,延迟 300ms 再恢复自动滚动(确保惯性完全停止)
|
||||||
clearTimeout(momentumTimer)
|
clearTimeout(momentumTimer)
|
||||||
momentumTimer = setTimeout(() => {
|
momentumTimer = setTimeout(() => {
|
||||||
isManualScrolling = false
|
isManualScrolling = false
|
||||||
resumeIOSAutoScroll()
|
autoScrollPos = currentScrollLeft
|
||||||
}, 1500)
|
startIOSAutoScroll()
|
||||||
|
}, 300)
|
||||||
} else {
|
} else {
|
||||||
// 惯性中,更新快照继续检测
|
// 惯性中,更新快照继续检测
|
||||||
lastTouchEndPos = currentScrollLeft
|
lastTouchEndPos = currentScrollLeft
|
||||||
@ -306,9 +305,7 @@ 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.value ? 'paused' : 'running',
|
'--play-state': iosScrollPaused ? 'paused' : 'running',
|
||||||
// 强制内联样式控制 animation-play-state
|
|
||||||
animationPlayState: iosScrollPaused.value ? 'paused' : 'running',
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -540,7 +537,7 @@ const batchGetPresignedUrls = async (urls) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loadUsers = async () => {
|
const loadUsers = async () => {
|
||||||
if (!isComponentMounted) return Promise.resolve()
|
if (!isComponentMounted) return
|
||||||
|
|
||||||
// 切换分类时重置偏移量
|
// 切换分类时重置偏移量
|
||||||
mockDataOffset = 0
|
mockDataOffset = 0
|
||||||
@ -761,11 +758,13 @@ 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 {
|
||||||
@ -926,32 +925,22 @@ watch(() => props.category, (newCategory) => {
|
|||||||
rafId = null
|
rafId = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// 父组件通过 key 变化来重置组件,这里不需要额外处理
|
loadUsers().then(() => {
|
||||||
// 延迟加载数据
|
nextTick(() => {
|
||||||
setTimeout(() => {
|
if (isIOS) {
|
||||||
loadUsersAndStartScroll()
|
startIOSAutoScroll()
|
||||||
}, 0)
|
} else {
|
||||||
|
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 {
|
||||||
@ -963,6 +952,7 @@ const loadUsersAndStartScroll = () => {
|
|||||||
|
|
||||||
.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 {
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
<!-- 横向瀑布流卡片层(内部自带横向滚动) -->
|
<!-- 横向瀑布流卡片层(内部自带横向滚动) -->
|
||||||
<WaterfallGrid
|
<WaterfallGrid
|
||||||
:key="waterfallKey"
|
|
||||||
:screenWidth="screenWidth"
|
:screenWidth="screenWidth"
|
||||||
:screenHeight="screenHeight"
|
:screenHeight="screenHeight"
|
||||||
:bannerBottom="bannerBottomPx"
|
:bannerBottom="bannerBottomPx"
|
||||||
@ -60,7 +59,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
|
import { ref, computed, 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'
|
||||||
@ -81,17 +80,10 @@ 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, () => {
|
|
||||||
// 切换标签时重置 WaterfallGrid(iOS 需要重新挂载才能重置 CSS 动画)
|
|
||||||
waterfallKey.value++
|
|
||||||
})
|
|
||||||
|
|
||||||
// ========== Screen Info ==========
|
// ========== Screen Info ==========
|
||||||
const screenWidth = ref(375)
|
const screenWidth = ref(375)
|
||||||
const screenHeight = ref(812)
|
const screenHeight = ref(812)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user