当前位置:首页 » 《随便一记》 » 正文

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

15 人参与  2024年09月21日 18:00  分类 : 《随便一记》  评论

点击全文阅读


一、帧的理解

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不会


点击全文阅读


本文链接:http://zhangshiyu.com/post/162871.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1