用requestAnimationFrame 做动画

340 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情

js requestAnimationFrame属性

1、认识requestAnimationFrame是什么

简而言之:requestAnimationFrame其实就是用来做动画的属性,用法上同setTimeout类似,并且可以匹配当前设备的刷新率,requestAnimationFrame() 通过自动匹配设备帧率来展示动画(多少帧就每秒执行多少次),做出可以匹配设备刷新率的动画

本质上:是一个浏览器的宏任务请求动画帧

2、作用

  • 代替定时器做更加流畅高性能的动画,也就是弥补定时器做动画不流畅的问题,
  • 高性能且可以解决setTimeout出现动画卡顿的问题
  • 弥补css无法实现的一些动画,比如:页面滚动

3、与setTimeout的相同和区分

【相同点】:

requestAnimationFrame与setTimeout都会返回一个唯一标识

【不同点】:

原理上

  • setTimeout利用递归来代替setInterval做简单的动画

  • requestAnimationFrame() 通过自动匹配设备帧率来展示动画

关闭定时器

  • 定时器上,setTimeout可以通过clearTImeout()关闭定时器。

  • requestAnimationFrame() 则使用cancelAnimationFrame()来关闭动画

参数上

  • setTimeout传入函数和时间

  • requestAnimationFrame这个方法只需要传入一个回调函数,不需要其他参数

时间间隔上

做动画都有一个时间间隔,requestAnimationFrame也有时间间隔

  • setTimeout由自定义的时间间隔来控制的

  • requestAnimationFrame与设备挂钩匹配(不受其他任务的影响)

回调函数执行次数上

  • setTimeout由自定义的时间间隔来控制的

  • requestAnimationFrame🉑️匹配设备,时间间隔上,requestAnimationFrame通常由我们传入的回调函数每秒会执行60次,但是如果你的设备的浏览器遵循W3c的标准,那么我们的函数每秒执行的次数会与你设备的刷新率相匹配。

动画运行上

  • setTimeout由自定义的时间间隔不断运行

  • requestAnimationFrame在大多浏览器中一旦页面不处于浏览器的当前标签,requestAnimationFrame就会自动停止动画。

刷新率和稳定性上

  • 使用定时器setTimeout做动画,假设显示器的刷新率为60hz【也就是每1秒播放60张动画】。为了让动画显示流畅,我们需要将定时器setTimeout的间隔时间定位 “1000/60”,【意思就是1000毫秒执行60次回调函数】,也就是1秒执行60次回调函数,大约每隔16.67毫秒会执行一次,这样就能匹配显示屏的帧率。但是依然还会有卡顿问题,因为定时器属于宏任务,而宏任务必须等待同步任务执行完成,再等微任务执行完成才会执行其中的回调函数,所以我们规定的时间间隔是不稳定并且不准确的。

  • requestAnimationFrame则匹配设备刷新率同步动画

4、使用

requestAnimationFrame的用法与setTimeout差不多,以一个元素上下移动的动画案例来对比

❤ setTimeout() 做元素上下移动动画:

const box = document.querySelector('.box'); //获取元素
let timer = setTimeout(function fn() {
        let move = parseInt(getComputedStyle(box).top);//顶部距离
	if (move < 800) {
		box.style.top = move + 8 + 'px';
		setTimeout(fn, 1000/60);
	} else {
           clearTimeout(timer);
	}
}, 1000/60);

❤ requestAnimationFrame() 做元素上下移动动画:

const box = document.querySelector('.box'); //获取元素
let timer = requestAnimationFrame(function fn() { 
    let move = parseInt(getComputedStyle(box).top);
	if (move < 800) {
		box.style.left = move + 8 + 'px';
		requestAnimationFrame(fn);
	} else {
            cancelAnimationFrame(timer);
	}
});

5、优缺点

优点:

  • 动画更加流畅
  • 高性能
  • 页面滚动

缺点:存在浏览器兼容问题

【兼容性问题处理-引用阮一峰大神的代码】

window.requestAnimFrame = (function(){
  return  window.requestAnimationFrame       || 
          window.webkitRequestAnimationFrame || 
          window.mozRequestAnimationFrame    || 
          window.oRequestAnimationFrame      || 
          window.msRequestAnimationFrame     || 
          function( callback ){
            window.setTimeout(callback, 1000 / 60);
          };
})();