60fps:如何正确使用requestAnimationFrame?

时间:2016-08-14 13:32:43

标签: javascript performance animation scroll

在我的网站上,当一个相关的内容框可见时,它应该被动画到视口中。

我正在尝试通过CSS和JavaScript尽可能提高我的动画效果,这样它就不会对滚动性能产生负面影响。

虽然CSS部分很简单(使用转换,将改变,包含),但我在使用window.requestAnimationFrame时遇到了一些麻烦。

我是否应该仅在将类添加到元素时使用它,或者在调用函数isScrolledIntoView时,或者甚至在isScrolledIntoView内时,在测量元素位置时使用它?

var percentVisible = 0.25;
window.addEventListener('scroll', function(){
relatedContent(related, percentVisible);
}
)

function relatedContent(r, pV){
    window.requestAnimationFrame(function() {
        if(isScrolledIntoView(r, pV)){
            window.requestAnimationFrame(function(){
                r.classList.add("visible");
             }, r)
        }
    }, r)
}

function isScrolledIntoView(el, percentV) {
var elemTop, elemBottom, elemHeight, overhang, isVisible;
/*window.requestAnimationFrame(
function(){*/
elemTop = el.getBoundingClientRect().top;
elemBottom = el.getBoundingClientRect().bottom;
elemHeight = el.getBoundingClientRect().height;
/*}
);*/
overhang = elemHeight * (1 - percentV);

isVisible = (elemTop >= -overhang) && (elemBottom <= window.innerHeight + overhang);
return isVisible;
}

2 个答案:

答案 0 :(得分:1)

不要不那样使用它......

  • requestAnimationFrame(rAF)是一个与屏幕刷新率同步的定时功能(通常为60fps)。
  • 滚动事件的触发次数可能超过每秒60次。
  • 每次调用rAF都会将所有作为参数传递的函数堆叠在下一次屏幕刷新之前调用的某个大函数中。

结合所有这些以及你得到的是在下一次屏幕刷新之前多次调用堆栈中的相同函数。

相反,您似乎想要的是防止滚动事件在无用时触发。这被称为油门功能,你离它有点远。

以下是使用rAF的简单限制实现:

var throttle = function(callback) {
  var active = false; // a simple flag
  var evt; // to keep track of the last event
  var handler = function(){ // fired only when screen has refreshed
    active = false; // release our flag 
    callback(evt);
    }
  return function handleEvent(e) { // the actual event handler
    evt = e; // save our event at each call
    if (!active) { // only if we weren't already doing it
      active = true; // raise the flag
      requestAnimationFrame(handler); // wait for next screen refresh
    };
  }
}

你可以这样使用:

window.addEventListener('scroll', throttle(yourScrollCallback));

答案 1 :(得分:1)

requestAnimationFrame returns a non-zero long可用于取消您的请求,因此,您可以使用以下更简单的方法来防止多个处理程序堆积,而不是编写自己的节流实现:

let currentRequest;
document.addEventListener('scroll', function () {
  cancelAnimationFrame(currentRequest);
  currentRequest = requestAnimationFrame(handleScroll);
});