JavaScript实现动画的常见方案
在JavaScript中实现动画本质是通过定时器或帧回调不断修改元素的样式属性,让视觉上产生连续变化的效果。目前主流的实现方案有三种,分别是基于setTimeout的实现、基于setInterval的实现,以及性能最优的基于requestAnimationFrame的实现。

1. 基于setTimeout的动画实现
setTimeout是最早期的动画实现方式,通过递归调用setTimeout,每隔固定时间修改元素样式,实现动画效果。这种方式的缺点是无法保证和浏览器刷新频率同步,可能会出现动画卡顿。
// 使用setTimeout实现元素向右移动的动画
let box = document.getElementById('box');
let position = 0;
// 动画执行的总时长 1000ms
let duration = 1000;
// 每帧移动的距离,假设60帧每秒,每帧移动约1.67px
let step = 200 / (duration / 16.7);
function move() {
position += step;
box.style.transform = 'translateX(' + position + 'px)';
if (position < 200) {
// 递归调用setTimeout,大约16.7ms后执行下一次移动
setTimeout(move, 16.7);
}
}
// 启动动画
move();2. 基于setInterval的动画实现
setInterval和setTimeout逻辑类似,不同的是它会按照固定时间间隔重复执行回调函数,不需要手动递归调用。同样存在和浏览器刷新帧不同步的问题,而且如果回调函数执行时间超过间隔时间,会出现执行堆积的问题。
let box = document.getElementById('box');
let position = 0;
let duration = 1000;
let step = 200 / (duration / 16.7);
// 每16.7ms执行一次样式修改
let timer = setInterval(function() {
position += step;
box.style.transform = 'translateX(' + position + 'px)';
if (position >= 200) {
// 动画结束后清除定时器
clearInterval(timer);
}
}, 16.7);3. 基于requestAnimationFrame的动画实现
requestAnimationFrame是浏览器专门为动画提供的API,它会在浏览器下一次重绘之前执行回调函数,和浏览器的刷新频率保持一致,动画流畅度远高于前两种方案,是当前实现JavaScript动画的首选方式。
let box = document.getElementById('box');
// 动画起始位置
let startPosition = 0;
// 动画结束位置
let endPosition = 200;
// 动画总时长
let duration = 1000;
// 记录动画开始的时间戳
let startTime = null;
function animate(timestamp) {
if (!startTime) {
startTime = timestamp;
}
// 计算当前动画已经执行的时间
let elapsed = timestamp - startTime;
// 计算当前进度,范围0到1
let progress = Math.min(elapsed / duration, 1);
// 根据进度计算当前位置
let currentPosition = startPosition + (endPosition - startPosition) * progress;
box.style.transform = 'translateX(' + currentPosition + 'px)';
if (progress < 1) {
// 动画未完成,继续执行下一帧
requestAnimationFrame(animate);
}
}
// 启动动画
requestAnimationFrame(animate);三种方案对比
三种动画实现方案的核心差异如下:
| 实现方案 | 性能表现 | 使用复杂度 | 适用场景 |
|---|---|---|---|
| setTimeout | 一般,可能卡顿 | 较低 | 简单低性能要求的动画 |
| setInterval | 一般,可能卡顿 | 较低 | 简单低性能要求的动画 |
| requestAnimationFrame | 优秀,和刷新帧同步 | 中等 | 所有对流畅度有要求的动画 |
动画实现注意事项
- 尽量使用
transform和opacity属性实现动画,这两个属性不会触发重排,性能更好 - 动画结束后及时清除定时器或者停止帧回调,避免不必要的性能消耗
- 如果需要兼容低版本浏览器,可以给requestAnimationFrame添加垫片处理
requestAnimationFrame在不支持的环境下可以通过setTimeout模拟实现,不过性能会有所下降,实际项目中建议优先使用原生API。
JavaScript动画实现requestAnimationFramesetTimeouttransform修改时间:2026-06-06 07:42:33