推迟工作,直到滚动结束

Web 功能: scrollend

在网页上滚动时,应顺畅且响应迅速。在滚动期间执行繁重的任务(例如布局重新计算、分析数据信标跟踪或动态 DOM 更新)可能会使主线程饱和,从而导致丢帧和布局抖动。

一直以来,开发者都依赖于使用 setTimeout() 对 scroll 事件进行去抖动,以猜测滚动何时结束。不过,众所周知,这些去抖动函数并不可靠。它们可能会在用户仍在滚动时触发。

scrollend 事件提供了一种高度可靠、以效果为导向的解决方案。当滚动停止、所有过渡完成且轻触手势释放时,浏览器会触发 scrollend 事件。

如何实现

如需实现延迟工作模式,请执行以下操作:

  1. 设置可滚动容器:使用 overflow: auto 或 overflow: scroll 创建容器。
  2. 监听 scroll 事件:仅将此监听器用于基本动态指标或信息性布局样式。请勿在此处执行繁重的工作。
  3. 监听 scrollend 事件:在滚动容器或文档本身上注册 scrollend 回调。
  4. 在回调中执行耗时的工作:此时可以安全地提取动态内容或触发全面的 DOM 布局。

示例代码

.scroll-container {
  height: 300px;
  overflow-y: auto;
}
const scroller = document.querySelector('.scroll-container');

// 1. Informative feedback during scroll
scroller.addEventListener('scroll', () => {
  // Avoid dynamic heavier data updates here
  console.log('Scrolling dynamically... updates deferred');
});

// 2. Safe callback when scrolling rests
scroller.addEventListener('scrollend', () => {
  // Run layout recalculations or analytical beacons updates here
  const currentVisibleSection = findMostVisibleSection(scroller);
  fetchAdditionalData(currentVisibleSection);
});

策略性实施和最佳实践

  • 务必在触发布局数据信标或动态提取新内容布局时使用 scrollend,而不是去抖动的 scroll 事件。
  • 务必考虑将此功能与 scrollSnapChange 或 scrollSnapChanging 贴靠互动搭配使用,以便构建轮播界面或客户评价库幻灯片。
  • 请勿在动态视觉滚动回调中捆绑依赖于布局的动态更新。
  • 务必考虑视觉视口缩放和滚动是否会正确触发 scrollend 事件。

后备策略

对于不受支持的浏览器,请回退到使用 setTimeout 的去抖动 scroll 事件,以分派自定义 scrollend 事件。

function initializeDemo() {
  const scroller = document.querySelector('#scroller');
  scroller.addEventListener('scrollend', () => {
    // Safe execution
  });
}

if ('onscrollend' in window) {
  initializeDemo();
} else {
  initializeDemo();
  const scroller = document.querySelector('#scroller');
  scroller.addEventListener('scroll', () => {
    clearTimeout(window.scrollendtimer);
    window.scrollendtimer = setTimeout(() => {
      scroller.dispatchEvent(new CustomEvent('scrollend'));
    }, 100);
  });
}