5

当页面隐藏时,Chrome 永远不会触发滚动事件,尽管页面实际上正在滚动。这看起来像是他们为减少不可见页面的 CPU 和网络使用而实施的。

有没有办法解决这种行为,即使使用 Chrome 的标志或扩展程序?我需要触发“滚动”事件,因为这是我正在测试的。

setInterval(() => {
    window.scrollBy(0, 100);
    // scrolls indefinitely even when the page is hidden
}, 1000);

addEventListener("scroll", () => {
    console.log("scroll " + document.documentElement.scrollTop);
    // however, this gets fired only if document.hidden is false
});

4

1 回答 1

2

这实际上是符合规范的。

滚动事件将作为更新事件循环的渲染步骤的一部分被触发。更新渲染可以按照其步骤 2 到 5 进行简化,其中当浏览器认为渲染无用时(例如,当文档被隐藏时),浏览器可以随意丢弃它。

所以即使滚动确实发生了,由于渲染还没有发生,所以没有事件被触发。

注意:在 Firefox 中添加调用requestAnimationFrame将强制事件触发几秒钟,但很快它们会显示 Chrome 限制所有rAF调用的行为,直到文档再次可见。

解决方法取决于您的具体情况。

如果您可以像示例中那样控制滚动的来源,那么自己触发它非常简单,甚至不需要事件。

setInterval(() => {
  window.scrollBy(0, 100);
  console.log("scroll " + document.documentElement.scrollTop);
}, 1000);
:root { height: 100000vh }

如果你不负责那个原始的setInterval,但知道它的频率,你也可以并行开始你自己的间隔:

setInterval(() => {
  window.scrollBy(0, 100);
}, 1000);
setInterval(() => {
  console.log("scroll " + document.documentElement.scrollTop);
}, 1000);
:root { height: 100000vh }

如果您不确定它是如何触发的,您可以覆盖所有滚动方法和设置器,以便它们也执行您的回调。

{
  // here we overwrite only scrollBy
  const orig = window.scrollBy;
  window.scrollBy = function(...args) {
    orig.call(this, ...args);
    console.log("scroll " + document.documentElement.scrollTop); 
  };
}

setInterval(() => {
  window.scrollBy(0, 100);
}, 1000);
:root { height: 100000vh }

如果您仍然需要确定是否确实发生了用户滚动,您可以通过仅在document.hidden为 true 时调用回调来调整所有这些变通方法,并让scroll事件处理其他事件。


PS:如果您担心平滑滚动,请注意浏览器在隐藏文档时不会更新平滑滚动位置。

于 2020-11-04T02:52:26.013 回答