JavaScript 动画实现原理与缓动算法详解
本文深入解析JavaScript动画的实现机制,对比setTimeout与requestAnimationFrame的性能差异,详解如何封装兼容API。重点介绍基于完成度p的Tween算法及多种缓动函数(如ease-in/out),通过数学公式实现匀加速、正弦等复杂运动效果,并探讨CSS3与JS动画的适用场景。
JavaScript动画概述
本文旨在基于现有知识体系,为读者提供了解JavaScript(以下简称JS)动画的入门视角。
JS如何制造出动画效果?
利用浏览器提供的 setInterval 或 setTimeout API,通过高频修改DOM元素的属性,即可生成肉眼可见的动画。一个流畅的JS动画不仅依赖于优秀的变换算法,还高度依赖执行环境。即使代码逻辑完美,若浏览器版本过旧或CPU性能不足,仍可能出现卡顿甚至死机现象。
requestAnimationFrame与性能优化
执行动画函数对浏览器而言是一项繁重任务。如何设定单帧时长以兼顾流畅度与性能?浏览器不会在每次DOM操作后立即渲染,而是将周期内的所有DOM操作合并,统一进行一次渲染。该周期约为16.7ms,不同浏览器存在几毫秒差异。因此,将SetTimeout的第二个参数设为 1000/60 较为合理。然而,SetTimeout的运行机制导致其时间并不精确,可能存在显著延迟。是否存在一种API,不关心浏览器具体渲染频率,仅在渲染时执行一帧动画?答案是 requestAnimationFrame,它使函数随浏览器渲染周期执行,且时机可靠。需注意,该方法仅在现代浏览器及IE10及以上版本中受支持。
现在可以封装一个简单的 requestAnimationFrame,后续示例将使用此封装。
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function( callback ){
window.setTimeout(callback, 1000 / 60);
};
})();
更详细的封装实现可参考张鑫旭博客:张鑫旭:requestAnimFrame。接下来继续探讨。
动画函数编写与核心变量
动画函数的编写
借助 requestAnimationFrame,接下来需考虑如何编写动画函数。通常需提供毫秒级的 during 参数,限定动画必须在指定时间内完成。以下以小球从页面左侧100px处匀速运动至800px处为例,编写动画函数:戳我查看DEMO。
var ele = document.getElementById("block");
var start = Date.now();//获取动画开始的时间。
var during = 1000; //此动画要在1秒内执行完。
var p=0;//动画完成度 从0-1;
requestAnimationFrame(function f(){
if(p>=1){ ele.style.left="800px";}//如果发现动画已经执行完,将元素置到终点。
else{
p=(Date.now()-start)/during;
ele.style.left=100+700*p+"px"; //从100px开始,匀速向右移动,共移动700px;
requestAnimationFrame(f);
}
})
上述函数中的关键变量 p(percentage,即动画完成度)根据当前时间计算得出,从动画开始起在0到1之间匀速渐变。当 p 为1时,表示动画执行完毕。在此函数中,将 p 乘以运动长度700,得到0至700的匀速变化值,加上起始位置100,即可模拟小球从100px处匀速移动至800px处。
若将上述红色标出的运动方程改为“ele.style.left=100+700*p*p+"px"”呢?由于 p 以二次方递增,小球向右移动的速度将逐渐加快。稍作修改即可实现匀加速运动的小球效果。
接下来,我们将针对 p 进行进一步处理。
Tween算法与缓动效果实现
Tween算法及缓动效果
以下列举常用缓动算法,通过修改上述匀速运动函数的运动方程,即可实现丰富的动画效果: 1.2次方缓动: p*p 2.3次方缓动: p*p*p 3.4次方缓动: p*p*p*p 4.5次方缓动: p*p*p*p*p 5.正弦曲线缓动: Math.sin(p*Math.PI/2) 6.指数曲线缓动: Math.pow(2,10*(p-1)) 7.圆形曲线缓动: Math.sqrt(1-(p-1)*(p-1)) 8.超范围三次方: p*p*(2.70158*p-1.70158)
验证一下,例如实现小球向右运动且带有向左蓄力效果的动画,只需将第一个demo的运动方程改为“ele.style.left=100+700*p*p*(2.70158*p-1.70158)+"px"”即可,效果见:戳我查看DEMO。
实际上,每种缓动算法均可演化为三种缓动方式:ease-in(先慢后快)、ease-out(先快后慢)以及 ease-in-out(先慢后快再慢)。
以2次方缓动为例,其本身即为匀加速过程,故 ease-in 对应 p*p。其 ease-out 形式为 -(p*(p-2))。关于缓动方式的详细说明,可参考阳光的博客:JavaScript动画、运动算法详细解释与分析。
接下来展示关于缓动整合的DEMO,戳我吧。
JS动画的应用场景与总结
JS动画可以做什么?
除上述缓动效果外,利用常见数学公式还可实现周期性运动,如小球匀速圆周运动、匀速简谐振动等。感兴趣者可猛戳DEMO。
那么JS动画能做什么?这需要发挥个人想象力。上述DEMO大多操控单一属性(如left),使DOM元素发生位移。事实上,在运动方程中,元素的任何style属性均可被渐变。例如,设置DOM元素的opacity从0到1进行2次方缓动,即可实现类似jQuery fadeOut函数的效果;让DOM元素高度从无到有,则对应简单的jQuery slideDown函数。更值得注意的是,动画过程中可同时操作多项属性,这为动画带来了无限可能性,使事情变得更加有趣:DEMO:一个从小到大变化的球。
再试想一下,若使用CSS3属性(如box-shadow、transform)制作效果,必将更加绚丽。
总结
前文提及使用CSS3属性,若浏览器支持CSS3,则完全无需使用JS。CSS3自带的Animation动画属性可简单快捷地实现酷炫效果,并支持GPU加速。其不足在于仅现代浏览器支持。JS实现动画的优势在于兼容低版本浏览器,但效果通常一般(仅限普通意义上的动画,不含canvas等)。
动画仅是JS操作DOM魅力的一角,数学与计算机的碰撞往往能迸发出耀眼火花。继续学习JS吧,这是一门神奇的语言,同时了解一些数学知识,往往能为解决问题提供捷径。
以上所述就是本文的全部内容了,希望大家能够喜欢。
JS在setTimeout或Ajax回调中打开新标签页失败怎么处理
2026-11-05 15:50:12
JS直播协议选型:HLS、FLV与WebRTC的延迟与兼容性对比
2026-11-05 12:16:14
JS实现回到顶部:scrollTop赋值与浏览器兼容性处理
2026-11-04 23:43:35
JS使用classList动态添加、移除和切换CSS类名
2026-11-04 23:40:58
在 D3.js 中实现平滑过渡动画的技巧
2026-11-03 23:46:09
