JavaScript - requestAnimationFrame使用

本文介绍requestAnimationFrame函数,一种跨浏览器的动画解决方案。通过回调函数实现动画效果,利用时间戳参数计算动画进度,适用于均匀及非均匀动画。提供代码示例,展示如何创建平滑动画。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目的

由于前端的浏览器兼容性问题,很多比较优雅的动画往往只在某些浏览器中可以使用,而在其它浏览器无效。所有浏览器都兼容的requestAnimationFrame便是用来解决这种问题。它能够按照规定的"路线"对帧进行更新,从而实现动画效果。

函数原型

window.requestAnimationFrame(callback) callback(DOMHighResTimeStamp), 参考MDN,该函数告诉浏览器执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。

该方法需要传入一个回调函数作为参数,回调函数会在浏览器下一次重绘之前执行。回调函数的参数为DOMHighResTimeStamp,十进制数值,表示网页加载完成后至今的毫秒数(即执行回调函数时的时间戳),与performace.now()的返回值相同。

具体来说,回调函数的内容一般是

callback(timestamp){
	根据timestamp计算需要更新的属性值
	更新属性值
	获得动画执行进度 ( 经历的时间值 = timestamp - 起始时间戳 )
	还需要继续动画 -> requestAnimationFrame(callback)
	不需要继续动画 -> return
}

调用requestAnimationFrame后浏览器的执行流程为:

收到动画请求 -> 调用回调函数,得到下一帧 -> 执行动画,从当前帧过渡到下一帧 ->  (回调函数调用requestAnimationFrame -> 重复) -> 结束 

使用回调函数的时间戳参数能够计算出从开始请求动画为止经历的时间,然后据此执行相应程度的更新,就可以实现动画效果了。

使用

回调函数的调用间隔很短,因此一般需要在回调函数内部再次调用requestAnimationFrame,以实现特定时长的动画,即

function callback(timeStamp){
    // ....... 更新元素属性
    requestAnimationFrame(callback);
}
requestAnimationFrame(callback);

如果是均匀的动画,那么只需根据执行时间百分比(由回调函数参数计算得到)更新属性,即在 x% 时刻更新元素的偏移为 x%·totalOffset。效果图如下

在这里插入图片描述

如果是非均匀的动画,那么在回调函数中需要手动计算下一帧的属性,然后执行更新即可。如下为使用函数 f ( x ) = 36 1 + e − x + 4 f(x)=\frac{36}{1+e^{-x+4}} f(x)=1+ex+436[0, 6 + 6]区间的值进行更新的效果图:

在这里插入图片描述

代码如下:

<!DOCTYPE html>
<html>
<head>
    <script>
        let totalTime = 850, zeroTimeStamp = 0;
        function moveByPercent() {
            let moveDistance = 600;
            let div = document.getElementById("container");
            function callback(timeStamp) {
                timeStamp = timeStamp - zeroTimeStamp;
                let x = timeStamp;
                let y = x / totalTime;
                let tmpLeft = y * moveDistance;
                div.style.left = (tmpLeft + 20) + 'px';
                if (timeStamp < totalTime) requestAnimationFrame(callback);
            };
            zeroTimeStamp = performance.now();
            requestAnimationFrame(callback);
        }
        function move() {
            let div = document.getElementById("container");
            // function: a / (1 + e^(-x + b))
            let moveDistance = 600;
            let a = 16, b = 4;
            let x_max = b + 6, y_max = a;
            function callback(timeStamp) {
                timeStamp = timeStamp - zeroTimeStamp;
                let x = timeStamp / totalTime * x_max;
                let y = a / (1 + Math.exp(-x + b));
                let tmpLeft = y / y_max * moveDistance;
                div.style.left = (tmpLeft + 20) + 'px';
                if (timeStamp < totalTime) requestAnimationFrame(callback);
            };
            zeroTimeStamp = performance.now();
            requestAnimationFrame(callback);
        }
    </script>
</head>
<body style="padding: 20px;margin: 0px;">
    <input type="button" value="moveByPercent" style="position: absolute;" onclick="moveByPercent()">
    <input type="button" value="move" style="position: absolute;margin-left: 200px;" onclick="move()">
    <div id="container"
        style="width: 300px;height: 300px;box-shadow: gray 1px 1px 6px;margin-top: 40px;position: absolute;background: cyan;">
    </div>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值