英文:
Detecting when finger is removed from touchpad but scroll is still happening due to "predictive touch" - JS
问题
我有一个处理滚动的函数,它会在一段时间内处理滚动。这个函数在用户使用鼠标滚轮滚动时起作用:
let shouldHandle = true
window.addEventListener('wheel', e => {
if (shouldHandle) {
handleScroll(e) // 我会在这里处理滚动
shouldHandle = false
setTimeout(() => {
shouldHandle = true
}, 750)
}
})
然而,当我使用笔记本电脑的触摸板滚动时,即使我移开手指,滚动仍然会发生(特别是当我加速移动手指并滚动,然后立即将手指从触摸板上移开时)。因此,即使在 750ms
后,滚动仍然会发生,即使用户技术上没有在滚动。关于这个问题已经在这里提出过。但是没有得到处理此行为的答案。
我想在最后一次滚动后经过一段时间才处理滚动。我想要处理的滚动不应该是因为这个“预测性触摸”滚动引起的。截止到目前,是否有方法可以实现这一点?
英文:
I have a function that handles scrolls every period of time. This function works when users scroll with mouse wheel:
let shouldHandle = true
window.addEventListener('wheel', e => {
if (shouldHandle) {
handleScroll(e) // I will handle scrolls here
shouldHandle = false
setTimeout(() => {
shouldHandle = true
}, 750)
}
})
However, when I am scrolling using my laptop's touchpad, scroll still happens even when I remove my finger (especially when I accelerate my finger enough and scroll, then immediately remove my finger from the touchpad). As a result, scroll still happens after the 750ms
even when the users are not technically scrolling. This question has been asked here. The question did not receive an answer to handle this behavior.
I want to handle scroll only after a period of time has elapsed from the last scroll. The scrolls I want to handle must not be because of scrolling caused by this "predictive touch" scroll. Is there a way to achieve this as of now?
答案1
得分: 3
处理这个问题的唯一方法,我想到的是在看到滚动开始后,监视scrollY
一段时间(可能每50毫秒轮询一次),等待它稳定下来(在相同位置X毫秒内,X的值由你决定),然后才认为滚动已经“完成”,然后启动750毫秒的计时器。不断轮询会不太好,但在滚动仍然活跃的时候,短时间内这样做似乎是可以接受的。
大致的草图(可能需要一个总的超时,例如):
// 非常粗糙地
let shouldHandle = true
let lastScrollY = null
let lastScrollTimer = 0
window.addEventListener('wheel', e => {
if (shouldHandle) {
handleScroll(e) // 我会在这里处理滚动
shouldHandle = false
waitForScrollEnd(() => {
setTimeout(() => {
shouldHandle = true
}, 750) // 或者根据`waitForScrollToEnd`中花费的最多50毫秒,也许设置为700
})
}
})
function waitForScrollEnd(cb) {
clearTimeout(lastScrollTimer)
lastScrollY = window.scrollY
lastScrollTimer = setTimeout(poll, 50)
function poll() {
if (lastScrollY === window.scrollY) {
lastScrollY = null
lastScrollTimer = 0 // 这是完全可选的,但与下面的`else`并行
cb()
} else {
lastScrollY = window.scrollY
lastScrollTimer = setTimeout(poll, 50)
}
}
}
英文:
The only way to handle that that comes to mind is to watch scrollY
for a period of time (polling, perhaps every 50ms or so) after you've seen a scroll start and wait for it to stabilize (X milliseconds in the same position, for whatever value of X you decide on) and only then consider that scroll "completed" and start your 750ms timer. Constantly polling would be bad, but doing it for a brief period while the scrolling is still actively occurring seems acceptable.
Rough sketch (could probably use an overall timeout, for instance):
// VERY ROUGHLY
let shouldHandle = true
let lastScrollY = null
let lastScrollTimer = 0
window.addEventListener('wheel', e => {
if (shouldHandle) {
handleScroll(e) // I will handle scrolls here
shouldHandle = false
waitForScrollEnd(() => {
setTimeout(() => {
shouldHandle = true
}, 750) // Or perhaps 700 on the basis that up to 50 was spent in `waitForScrollToEnd`
})
}
})
function waitForScrollEnd(cb) {
clearTimeout(lastScrollTimer)
lastScrollY = window.scrollY
lastScrollTimer = setTimeout(poll, 50)
function poll() {
if (lastScrollY === window.scrollY) {
lastScrollY = null
lastScrollTimer = 0 // This is entirely optional but makes it parallel with the `else` below
cb()
} else {
lastScrollY = window.scrollY
lastScrollTimer = setTimeout(poll, 50)
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论