简体   繁体   English

60fps:如何正确使用requestAnimationFrame?

[英]60fps: How to use requestAnimationFrame the right way?

On my website, a related content box should be animated into the viewport when it gets visible. 在我的网站上,相关的内容框在可见时应设置为动画。

I'm trying to make my animation as efficient as possible through CSS and JavaScript, so that it doesn't affects scroll performance negatively. 我试图通过CSS和JavaScript使动画尽可能高效,以免对滚动性能产生负面影响。

While the CSS part was simple (using transform, will-change, contain), I'm struggling a bit with when to use window.requestAnimationFrame . 虽然CSS部分很简单(使用transform,will-change,contain),但我在何时使用window.requestAnimationFrame有些挣扎。

Should I use it only when the class is added to the element or also when the function isScrolledIntoView is called or even inside isScrolledIntoView , when the elements position is measured? 我应该仅在将类添加到元素时使用它还是在调用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;
}

No don't use it like that... 不,不要那样使用...

  • requestAnimationFrame (rAF) is a timing function that does synchronize with the screen refresh rate (generally 60fps). requestAnimationFrame(rAF)是一种计时功能,与屏幕刷新率(通常为60fps)同步。
  • Scroll event may fire more often than 60 events per second. 滚动事件每秒可能会触发60次以上的事件。
  • Each call to rAF will stack all the functions passed as its parameter in some kind of a big function called just before the next screen refresh. 每次对rAF的调用都会将作为其参数传递的所有函数堆叠在某种大函数中,该函数在下一次屏幕刷新之前被调用。

Combine all of this and what you get is multiple calls to the same function in a stack, just before the next screen refresh. 将所有这些结合起来,就可以在下一个屏幕刷新之前在堆栈中多次调用同一个函数。

Instead, what you seem to want is to prevent your scroll event to fire when not useful. 相反,您似乎想要的是防止滚动事件在不可用时触发。 This is called a throttle function, and you're a bit far from it. 这称为节流功能,您离它有点远。

Here is a simple throttle implementation using 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
    };
  }
}

That you could use like this : 您可以这样使用:

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

requestAnimationFrame returns a non-zero long that can be used to cancel your request, so instead of writing your own throttle implementation, you can use the following simpler approach to prevent multiple handlers stacking up: requestAnimationFrame 返回一个非零long requestAnimationFrame ,可用于取消您的请求,因此您可以使用以下更简单的方法来防止多个处理程序堆积,而不是编写自己的节流实现:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM