使用 requestAnimationFrame 替换 $(window).on('scroll', function(

Is it safe to use requestAnimationFrame to replace $(window).on('scroll', function(){});?

本文关键字:scroll function 替换 requestAnimationFrame window 使用 on      更新时间:2023-09-26

当用户滚动时,我需要每±100毫秒知道当前的滚动位置。该位置决定了页面的哪个部分被"照亮"。

有了$(window).on('scroll', function(){});一切正常。我使用 _.debounce 对事件进行去反弹,并在文档现在所在的位置每 100 毫秒签入一次。

但是 - 在iPad上 - 在滚动完全停止之前不会触发"滚动">,这在我的场景中很糟糕,所以我正在尝试找出更好的解决方案。

起初,我想使用setInterval并以这种方式每 100 毫秒检查一次位置,但我读到它在移动设备上效率不高,即使选项卡没有打开,它也会运行。所以我偶然发现了requestAnimationFrame,目前,看起来我可以做到这一点:

saved_pos = -1;
rAF = window.requestAnimationFrame;
set_sticky_pos = function() {
  if (saved_pos === window.scrollY) {
    rAF(set_sticky_pos);
    return false;
  }
  saved_pos = window.scrollY;
  debounced_trigger_function(saved_pos);
  rAF(set_sticky_pos);
};

然后,我的debounced_trigger_function将检查当前位置,并根据它通过在其父元素上添加一个类来阐明所需的内容。

通过这样做 - 有什么我应该注意的吗?这是一个很大的禁忌吗?

注意:您可能已经注意到,我没有做任何真正的"动画",这是(我认为(rAF的实际设计目的,但这似乎是对抗iPad上缓慢的唯一方法。这正是我决定在 SO 上发布问题的原因 - 即使我不"动画"也可以使用 rAF 吗?

博士

是否可以使用 rAF 作为实时滚动位置检测的解决方法,而不是用于"动画"?

由于iOS设备使用的是webkit浏览器,因此您可以使用一行CSS实现平滑滚动:

-webkit-overflow-scrolling: touch;

如果这对您不起作用,则可以将rAF与自定义的polyfill一起使用,如果rAF不可用,则可以回退到滚动,但这很容易验证:

window.requestAnimFrame = (function(){
  return  window.requestAnimationFrame       ||
          window.webkitRequestAnimationFrame ||
          window.mozRequestAnimationFrame    ||
          function( callback ){
            // defualt scrolling logic or setInterval
            window.setTimeout(callback, 1000 / 60);
          };
})();

此外,如果您不想弄乱桌面浏览器上的默认滚动,您可以使用 Modernizr 来检测运行代码的设备是否启用了触摸,并且比(并且仅比(您可以覆盖默认滚动行为。这将像

if(Modernizr.touch) {
    // your custom scrolling logic here, rAF for example
}