RequestAnimationFrame实现动画总结

4,107 阅读3分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战

本文主要整理一些requestAnimationFrame的知识点,感觉有用请点赞。

requestAnimationFrame最简单的用法

requestAnimationFrame类似于setInterval,但是写法有些不同。它的写法是有套路的,类似于下面:

//1. 执行动画
function start(){
   requestAnimationFrame(loop)
}
// 2.动画循环
function loop(){
    animateLogic()
    requestAnimationFrame(loop)
}
//3. 动画具体逻辑
function animateLogic(){
    //在这里写动画的具体逻辑,可以是处理元素的位置信息,也可以是修改某个数据(用于数据驱动视图的框架,例如vue,react)
    console.log(+new Date())
}

这样就实现了一个最简单的动画循环,调用start()开始动画,然后就会递归执行loop,大概16ms执行一次动画,可以在控制台看一下打印的内容,也可以修改animateLogic的里面的代码,操作一个dom元素的属性,看看效果。

其实这样的写法刚接触的人是有疑惑的,你可能会疑惑这样写会不会造成函数栈溢出,这样写会不会造成性能问题,为什么不用setInterval,浏览器是如何保证这个API的性能的,有疑惑的人看下这篇文章:stackoverflow.com/questions/3…

实现了最简单的用法之后,来下一个问题

上面那样执行动画太快了,我如何控制动画的执行间隔

假如我想让动画每1000ms执行一次,如何处理?

首先requestAnimationFrame(callback),回调函数callback会有一个参数,表示当前时间currentTime, 我们定义一个时间间隔duration,定义一个变量nextTime表示动画下次执行时间。

在每次动画循环中,判断当前时间currentTime是否大于等于nextTime,如果等于,执行动画逻辑,否则直接去下一次动画循环,代码如下:

let nextTime=0  // 下次动画执行开始时间
let duration=1000 //动画间隔时间1000ms

//1. 执行动画
function start(){
   requestAnimationFrame(loop)
}
// 2.动画循环
function loop(currentTime){
    if(currentTime<nextTime){
        requestAnimationFrame(loop)
        return 
    }
    nextTime=currentTime+duration

    animateLogic()
    requestAnimationFrame(loop)
}
//动画逻辑
function animateLogic(){
    //在这里写动画的具体逻辑,可以是处理元素的位置信息,也可以是修改某个数据(用于数据驱动视图的场景,例如vue,react)
    console.log(+new Date())
}

可以执行一下以上代码看一下控制台打印

接下来,下一个问题,

如何停止动画呢

最简单的办法,定义一个变量pause,用来控制动画是否停止

let nextTime=0  // 下次动画执行开始时间
let duration=1000 //动画间隔时间1000ms

let pause=false //定义变量,控制动画状态
//1. 执行动画
function start(){
    pause=false
   requestAnimationFrame(loop)
}
function stop(){
    pause=true
}
// 2.动画循环
function loop(currentTime){
    if(currentTime<nextTime){
        requestAnimationFrame(loop)
        return 
    }
    nextTime=currentTime+duration
    if(!pause){
        animateLogic()
    }
    requestAnimationFrame(loop)
}
//动画逻辑
function animateLogic(){
    //在这里写动画的具体逻辑,可以是处理元素的位置信息,也可以是修改某个数据(用于数据驱动视图的场景,例如vue,react)
    console.log(+new Date())
}

此外,浏览器还提供另外一个API,cancelAnimationFrame用来取消动画,不过用起来有点麻烦,参考以下文章: stackoverflow.com/questions/1…

基本使用到此为止,下篇文章写点实际应用.

see you.