Scrollend(一种新的 JavaScript 事件)

删除超时函数并摆脱其 bug,您真正需要的是:scrollend 事件。

Adam Argyle
Adam Argyle

scrollend 事件之前,没有可靠的方法来检测滚动是否已完成。这意味着事件会延迟触发,或者在用户的手指仍按在屏幕上时触发。这种无法确定滚动何时实际结束的不确定性导致了 bug 和用户体验不佳。

之前
document.onscroll = event => {
  clearTimeout(window.scrollEndTimer)
  window.scrollEndTimer = setTimeout(callback, 100)
}

setTimeout() 策略能做的最多就是知道 100ms 是否已停止滚动。这更像是滚动已暂停事件,而不是滚动已结束事件。

scrollend 事件发生后,浏览器会为您执行所有这些高难度的评估。

之后
document.onscrollend = event => {}

太好了。在发射之前,时间安排得当且包含大量有意义的条件。

浏览器支持

  • Chrome:114.
  • 边缘:114。
  • Firefox:109.
  • Safari:不受支持。

来源

试试看!

活动详情

在以下情况下,系统会触发 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 和实现指导。