feat: 添加瀑布流滚动的安卓和ios的判断
This commit is contained in:
parent
b68ca3e7be
commit
5208bde803
@ -2,8 +2,8 @@
|
||||
"name" : "TopFans",
|
||||
"appid" : "__UNI__F199FF4",
|
||||
"description" : "",
|
||||
"versionName" : "1.0.3",
|
||||
"versionCode" : 100,
|
||||
"versionName" : "1.0.4",
|
||||
"versionCode" : 101,
|
||||
"transformPx" : false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
@ -23,7 +23,8 @@
|
||||
"modules" : {
|
||||
"VideoPlayer" : {},
|
||||
"Camera" : {},
|
||||
"Speech" : {}
|
||||
"Speech" : {},
|
||||
"Push" : {}
|
||||
},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
@ -70,12 +71,7 @@
|
||||
"secretkey" : "1i5Aj8FwL3i11LYPeXMRwRWycictWq2X"
|
||||
}
|
||||
},
|
||||
"push" : {
|
||||
"unipush" : {
|
||||
"version" : "2",
|
||||
"offline" : false
|
||||
}
|
||||
}
|
||||
"push" : {}
|
||||
},
|
||||
"icons" : {
|
||||
"android" : {
|
||||
|
||||
@ -78,8 +78,8 @@ const GAP = rpx2px(16)
|
||||
const BORDER_W = rpx2px(2)
|
||||
const SCALE = 0.9
|
||||
const ROWS = 4
|
||||
const AUTO_SCROLL_SPEED = 0.1
|
||||
const AUTO_RESUME_DELAY = 1000
|
||||
const AUTO_SCROLL_SPEED = 0.3
|
||||
const AUTO_RESUME_DELAY = 1500
|
||||
const PRELOAD_THRESHOLD = rpx2px(300)
|
||||
|
||||
// ========== 状态 ==========
|
||||
@ -112,62 +112,34 @@ let rafId = null
|
||||
let userInteracting = false
|
||||
let resumeTimer = null
|
||||
let appendTimer = null // 防抖定时器
|
||||
let autoScrollPos = 0 // 自动滚动目标位置
|
||||
let momentumTimer = null // iOS 惯性滚动检测定时器
|
||||
let scrollUpdateTimer = null // 定期同步 scrollLeft 的定时器
|
||||
|
||||
const startAutoScroll = () => {
|
||||
if (!isComponentMounted) {
|
||||
return
|
||||
}
|
||||
// 确保没有重复的 RAF 在运行
|
||||
if (!isComponentMounted) return
|
||||
if (rafId) {
|
||||
cafFn(rafId)
|
||||
rafId = null
|
||||
}
|
||||
// 重置滚动状态
|
||||
userInteracting = false
|
||||
autoScrollPos = currentScrollLeft
|
||||
|
||||
let lastScrollLeft = 0 // 用于检测手动滚动
|
||||
// 使用定时器定期更新 scrollLeft
|
||||
clearInterval(scrollUpdateTimer)
|
||||
scrollUpdateTimer = setInterval(() => {
|
||||
if (!isComponentMounted || userInteracting || isLoadingMore) return
|
||||
autoScrollPos += AUTO_SCROLL_SPEED
|
||||
scrollLeft.value = autoScrollPos
|
||||
|
||||
const step = () => {
|
||||
if (!isComponentMounted) {
|
||||
rafId = null
|
||||
return
|
||||
}
|
||||
// 每次 RAF 循环开始时也检查一次
|
||||
if (!isComponentMounted) {
|
||||
rafId = null
|
||||
return
|
||||
}
|
||||
|
||||
if (!userInteracting && !isLoadingMore) {
|
||||
// 检测是否被手动滚动过(如果实际滚动位置和我们的不一致,说明用户手动滚了)
|
||||
const actualScroll = scrollLeft.value
|
||||
if (Math.abs(actualScroll - lastScrollLeft) > 5) {
|
||||
// 用户手动滚了,同步位置
|
||||
currentScrollLeft = actualScroll
|
||||
} else {
|
||||
// 正常累加
|
||||
currentScrollLeft += AUTO_SCROLL_SPEED
|
||||
scrollLeft.value = currentScrollLeft
|
||||
lastScrollLeft = currentScrollLeft
|
||||
// 预加载
|
||||
const remainingScroll = totalWidth.value - autoScrollPos - props.screenWidth
|
||||
if (remainingScroll < Math.max(totalWidth.value / 2, props.screenWidth)) {
|
||||
if (!isLoadingMore && !appendFailed && !isInitialLoading && props.useMockData) {
|
||||
appendMore()
|
||||
}
|
||||
|
||||
// 预加载:剩余可滚动距离小于一半屏幕宽度时,触发追加
|
||||
const remainingScroll = totalWidth.value - currentScrollLeft - props.screenWidth
|
||||
if (remainingScroll < Math.max(totalWidth.value / 2, props.screenWidth)) {
|
||||
// 直接调用 appendMore(不需要防抖)
|
||||
// 注意:真实接口模式下不应该自动追加数据,由 has_more 控制
|
||||
if (!isLoadingMore && !appendFailed && !isInitialLoading && props.useMockData) {
|
||||
appendMore()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 用户交互中,记录当前滚动位置
|
||||
lastScrollLeft = scrollLeft.value
|
||||
currentScrollLeft = lastScrollLeft
|
||||
}
|
||||
rafId = rafFn(step)
|
||||
}
|
||||
rafId = rafFn(step)
|
||||
}, 16)
|
||||
}
|
||||
|
||||
const stopAutoScroll = () => {
|
||||
@ -175,21 +147,41 @@ const stopAutoScroll = () => {
|
||||
cafFn(rafId)
|
||||
rafId = null
|
||||
}
|
||||
clearInterval(scrollUpdateTimer)
|
||||
scrollUpdateTimer = null
|
||||
clearTimeout(appendTimer)
|
||||
appendTimer = null
|
||||
clearTimeout(resumeTimer)
|
||||
resumeTimer = null
|
||||
clearTimeout(momentumTimer)
|
||||
momentumTimer = null
|
||||
userInteracting = false
|
||||
isLoadingMore = false
|
||||
}
|
||||
|
||||
const pauseForUser = () => {
|
||||
userInteracting = true
|
||||
clearTimeout(resumeTimer)
|
||||
resumeTimer = setTimeout(() => { userInteracting = false }, AUTO_RESUME_DELAY)
|
||||
// 检测 iOS 惯性滚动是否结束
|
||||
let lastTouchEndPos = 0 // touchend 时的位置快照
|
||||
|
||||
const detectMomentumEnd = () => {
|
||||
clearTimeout(momentumTimer)
|
||||
lastTouchEndPos = currentScrollLeft
|
||||
const tick = () => {
|
||||
momentumTimer = setTimeout(() => {
|
||||
// 比较的是 lastTouchEndPos(touchend 时的位置),不受后续惯性影响
|
||||
if (Math.abs(currentScrollLeft - lastTouchEndPos) < 3) {
|
||||
autoScrollPos = currentScrollLeft
|
||||
startAutoScroll()
|
||||
} else {
|
||||
// 惯性中,更新快照
|
||||
lastTouchEndPos = currentScrollLeft
|
||||
tick()
|
||||
}
|
||||
}, 60)
|
||||
}
|
||||
tick()
|
||||
}
|
||||
|
||||
// 防抖:延迟 500ms 后再执行追加,避免频繁调用
|
||||
// 防抖:延迟追加
|
||||
const scheduleAppend = () => {
|
||||
if (!isComponentMounted || appendFailed) return
|
||||
if (appendTimer) clearTimeout(appendTimer)
|
||||
@ -202,16 +194,23 @@ const scheduleAppend = () => {
|
||||
}
|
||||
|
||||
// ========== 触摸 / 滚动事件 ==========
|
||||
const onTouchStart = () => pauseForUser()
|
||||
const onTouchEnd = () => {}
|
||||
const onTouchStart = () => {
|
||||
userInteracting = true
|
||||
clearTimeout(momentumTimer)
|
||||
clearInterval(scrollUpdateTimer)
|
||||
}
|
||||
|
||||
const onTouchEnd = () => {
|
||||
// 等待 iOS 惯性滚动自然结束,再决定是否恢复自动滚动
|
||||
detectMomentumEnd()
|
||||
}
|
||||
|
||||
const onScroll = (e) => {
|
||||
if (!isComponentMounted) return
|
||||
currentScrollLeft = e.detail.scrollLeft
|
||||
// 预加载:剩余可滚动距离小于一半屏幕宽度时,触发追加
|
||||
|
||||
const remainingScroll = totalWidth.value - currentScrollLeft - props.screenWidth
|
||||
if (remainingScroll < Math.max(totalWidth.value / 2, props.screenWidth)) {
|
||||
// 注意:真实接口模式下不应该自动追加数据,由 has_more 控制
|
||||
if (!isLoadingMore && !appendFailed && !isInitialLoading && props.useMockData) {
|
||||
scheduleAppend()
|
||||
}
|
||||
@ -681,12 +680,16 @@ onMounted(() => {
|
||||
const handleVisibilityChange = () => {
|
||||
if (!isComponentMounted) return
|
||||
if (document.hidden) {
|
||||
userInteracting = true
|
||||
stopAutoScroll()
|
||||
} else {
|
||||
userInteracting = false
|
||||
if (!rafId) {
|
||||
startAutoScroll()
|
||||
}
|
||||
// 页面重新可见时,延迟启动自动滚动,等待视图稳定
|
||||
stopAutoScroll()
|
||||
setTimeout(() => {
|
||||
if (isComponentMounted) {
|
||||
autoScrollPos = currentScrollLeft
|
||||
startAutoScroll()
|
||||
}
|
||||
}, 150)
|
||||
}
|
||||
}
|
||||
|
||||
@ -698,12 +701,15 @@ if (typeof document !== 'undefined') {
|
||||
watch(() => props.isActive, (active) => {
|
||||
if (!isComponentMounted) return
|
||||
if (active) {
|
||||
userInteracting = false
|
||||
if (!rafId) {
|
||||
startAutoScroll()
|
||||
}
|
||||
stopAutoScroll()
|
||||
setTimeout(() => {
|
||||
if (isComponentMounted) {
|
||||
autoScrollPos = currentScrollLeft
|
||||
startAutoScroll()
|
||||
}
|
||||
}, 150)
|
||||
} else {
|
||||
userInteracting = true
|
||||
stopAutoScroll()
|
||||
}
|
||||
}, { immediate: false })
|
||||
|
||||
@ -712,6 +718,7 @@ onUnmounted(() => {
|
||||
stopAutoScroll()
|
||||
clearTimeout(resumeTimer)
|
||||
clearTimeout(appendTimer)
|
||||
clearTimeout(momentumTimer)
|
||||
if (typeof document !== 'undefined') {
|
||||
document.removeEventListener('visibilitychange', handleVisibilityChange)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user