0


【JS动画】帧的理解与requestAnimationFrame的使用

一、帧的理解

1、帧

帧是影像或动画中的最小单位,相当于电影胶片上的每一格画面

2、帧数和帧率

  • 帧数:指一段时间内,产生的或者播放的帧的数量
  • 帧率:指一秒内产生的或者播放的帧的数量,单位为FPS,frames per second

二、requestAnimationFrame的使用

**

window.requestAnimationFrame()

** 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。其通常执行回调函数的频率为每秒60次(约16.6ms刷新一次)。当然其刷新次数也与当下浏览器屏幕刷新次数相匹配。

1、执行刷新回调

通常,requestAnimationFrame与回调函数会构成循环嵌套,从而实现持续地帧刷新。

形如下:

function frame(){
    //下一帧的渲染逻辑:例如修改canvas图形的offset等、重新计算元素的transform属性值
    .....

    //停止下一次的帧刷新    
    if(终结判断 为真) return

    requestAnimationFrame(frame)
}

值得注意的是,当在class类中定义frame函数,并用将其作为回调函数时,一定要注意利用箭头函数解决this指向的问题 !直接requestAnimationFrame(this.frame)会使得this指向调用者window!

正确写法如下:

class Renderer{
    ...
    frame(){

        //下一帧的渲染逻辑:例如修改canvas图形的offset等、重新计算元素的transform属性值
        .....

        //停止下一次的帧刷新    
        if(终结判断 为真) return

        requestAnimationFrame(()=>this.frame())

    }

}

此时,利用箭头函数的特性【即this指向的是函数定义时,外部最近作用域中的this对象】,才可以准确调用frame函数

2、timestamp传参

该回调函数会传入 DOMHighResTimeStamp 参数,该参数与 performance.now() 的返回值相同,它表示

requestAnimationFrame()

开始执行回调函数的时刻。

*注意:若在同一帧时间内传入多个回调函数,每个回调函数中的timestamp值是相同的!

performance.now()与一些js中的time类(例如Date.now())不同的是,它不仅仅可以精确到一毫秒,而且可以以毫秒为单位作为浮点数返回,最大可精确到微秒级别

因此,当我们可以显示声明回调函数中的timestamp参数,从而准确计算这一帧中的物体状态。

例如:

const element = document.getElementById("some-element-you-want-to-animate");
let start, previousTimeStamp;
let done = false;

function step(timestamp) {
  if (start === undefined) {
    start = timestamp;
  }
  const elapsed = timestamp - start;

  if (previousTimeStamp !== timestamp) {
    // 这里使用 Math.min() 确保元素在恰好位于 200px 时停止运动
    const count = Math.min(0.1 * elapsed, 200);
    element.style.transform = `translateX(${count}px)`;
    if (count === 200) done = true;
  }

  if (elapsed < 2000) {
    // 2 秒之后停止动画
    previousTimeStamp = timestamp;
    if (!done) {
      window.requestAnimationFrame(step);
    }
  }
}

window.requestAnimationFrame(step);

3、取消动画帧的渲染

requestAnimationFrame的返回值是一个long类型的非0值,可理解为请求DI,作为回调列表中的唯一标识。

我们可以利用这个ID值,传入window.cancelAnimationFrame() 以取消相应的回调函数请求。

为提高性能和延长电池寿命,当**浏览器将标签页切换至后台 ** 或者 在隐藏的<iframe>里 时,requestAnimationFrame将会暂停调用执行。

三、为什么不用setInterval进行动画帧的刷新

setInterval属于定时器,即间隔一段时间后执行代码内容。

由于JS的执行是单线程的,其遵循事件循环(event loop)机制。而setInterval定时执行回调函数属于宏任务,这种执行顺序会导致其隐藏时间误差。

如果将setInterval作为帧刷新的控制器,其在长时间执行后,由于时间误差的累积,效果会越来越不理想!从而导致动画闪烁等情况

另外,在性能方面,requestionAnimationFrame在切换标签页至后台时,会自动停止执行,而setInterval不会


本文转载自: https://blog.csdn.net/weixin_57208584/article/details/140415402
版权归原作者 音仔小瓜皮 所有, 如有侵权,请联系我们删除。

“【JS动画】帧的理解与requestAnimationFrame的使用”的评论:

还没有评论