删除超时函数并消除其 bug,以下是您真正需要的事件:scrollend。
在 scrollend
事件之前,没有可靠的方法来检测滚动是否已完成。这意味着,事件会延迟或用户的手指仍在屏幕上时触发。无法可靠地知道滚动实际何时结束,会导致 bug 以及糟糕的用户体验。
document.onscroll = event => { clearTimeout(window.scrollEndTimer) window.scrollEndTimer = setTimeout(callback, 100) }
此 setTimeout()
策略能做到的最棒的就是,了解 100ms
的滚动操作是否已停止。这更像是滚动暂停事件,而不是滚动结束事件。
在 scrollend
事件之后,浏览器会为您执行所有这些艰难的评估。
document.onscrollend = event => {…}
这些都很棒。在发出前,经过完美计时和充分考虑有利条件。
试试看!
活动详情
在以下情况下,会触发 scrollend
事件:
- 浏览器不再以动画形式呈现或停止转换滚动操作。
- 用户的触摸动作已释放。
- 用户的指针释放了滚动滑块。
- 用户的按键已释放。
- 滚动到 fragment 已完成。
- 滚动贴靠已完成。
- scrollTo()
已完成。
- 用户滚动了可视化视口。
在以下情况下,scrollend
事件不会触发:
- 用户手势未导致任何滚动位置更改(未发生平移)。
- scrollTo()
未得到任何翻译。
此事件之所以花费如此之久才出现在 Web 平台中,是因为许多小细节需要规范细节。其中最复杂的领域之一是,清晰展示视觉视口与文档的 scrollend
详细信息。以您要放大的网页为例。在此缩放状态下,您可以滚动,而不一定会滚动文档。请放心,即使这种视觉视口用户驱动的滚动互动操作完成后,也会发出 scrollend
事件。
使用事件
与其他滚动事件一样,您可以通过多种方式注册监听器。
addEventListener("scrollend", (event) => {
// scroll ended
});
aScrollingElement.addEventListener("scrollend", (event) => {
// scroll ended
});
或者,使用 event 属性:
document.onscrollend = (event) => {
// scroll ended
};
aScrollingElement.onscrollend = (event) => {
// scroll ended
};
Polyfill 和渐进式增强
如果您打算立即使用这项新活动,请查看我们这里的最佳建议。您可以继续使用当前的滚动结束策略(如果有),并在开始利用以下策略检查支持情况:
'onscrollend' in window
// true, if available
这将报告 true 或 false,具体取决于浏览器是否提供该事件。通过这项检查,您可以分支代码:
if ('onscrollend' in window) {
document.onscrollend = callback
}
else {
document.onscroll = event => {
clearTimeout(window.scrollEndTimer)
window.scrollEndTimer = setTimeout(callback, 100)
}
}
因此,在 scrollend
事件可用时,可以先逐步对其进行增强。您还可以尝试使用我开发的 polyfill (NPM),它在浏览器方面能够实现最佳效果:
import {scrollend} from "scrollyfills"
// then use scrollend as if it's existed this whole time
document.onscrollend = callback
Polyfill 会逐渐增强,以使用浏览器内置的 scrollend
事件(如果有)。如果该事件不可用,脚本会监视指针事件并滚动,以尽可能准确地估算事件结束。
用例
最好避免发生滚动时计算繁重的工作。这种做法可确保滚动操作可以自由地使用尽可能多的内存和处理,以保持流畅的体验。由于不会再发生滚动,因此使用 scrollend
事件可为您提供绝佳机会来发出调用并完成这项艰巨工作。
scrollend
事件可用于触发各种操作。一个常见的用例是将关联的界面元素与滚动停止的位置同步。例如:
- 将轮播界面滚动位置与圆点指示器同步。
- 将图库项与其元数据同步。
- 在用户滚动到新标签页后提取数据。
设想一个用户滑开电子邮件的场景。用户完成滑动后,您可以根据他们滚动到的位置执行操作。
您也可以在程序化操作或用户滚动后或执行日志记录分析等操作之后使用此事件进行同步。
下面是一个很好的示例,其中多个元素(如箭头、点和焦点)需要根据滚动位置进行更新。观看我如何在 YouTube 上制作此轮播界面。另外,您还可以试用现场演示。
感谢 Mehdi Kazemi 对此做出的工程工作,以及 Robert Flack 提供的 API 和实现指南。