应使用animationend或transitionend事件监听CSS动画/过渡结束,而非setTimeout;需过滤animationName、处理infinite动画、兼容旧Safari,并在回调中先清动画、强制重排再改样式。

JavaScript 中实现动画结束后的回调,主要依赖 animationend 事件(CSS 动画)或 transitionend 事件(CSS 过渡),也可以用 requestAnimationFrame 或定时器手动控制 JS 动画的完成时机。关键是要区分动画类型,并正确监听和清理事件。
监听 CSS 动画结束(animationend)
当使用 @keyframes 定义 CSS 动画时,在元素上触发动画后,可通过 animationend 事件捕获结束时刻:
- 该事件只在动画**正常播放完成**时触发(不包括被
animation-play-state: paused暂停、或被新动画覆盖中断的情况) - 需注意浏览器兼容性,部分旧版 Safari 使用
webkitAnimationEnd - 建议添加一次性的事件监听器,避免重复执行;可用
{ once: true }选项
const el = document.getElementById('box');
el.addEventListener('animationend', () => {
console.log('CSS 动画已结束');
// 执行回调逻辑,如移除 class、启用按钮、切换状态等
}, { once: true });监听 CSS 过渡结束(transitionend)
对 transform、opacity 等可过渡属性做变化时,用 transitionend 更合适:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 一个元素若有多个过渡属性(如同时改
width和opacity),会触发多次transitionend,需通过event.propertyName判断是哪个属性结束 - 若只关心某一个属性(如只等
transform结束),可加判断条件 - 同样推荐使用
{ once: true }防止重复回调
el.addEventListener('transitionend', (e) => {
if (e.propertyName === 'transform') {
console.log('transform 过渡已完成');
// 执行后续操作
}
}, { once: true });JS 动画(requestAnimationFrame)的手动回调
若用 requestAnimationFrame 自行实现逐帧动画(例如缓动滚动、Canvas 动画),没有内置结束事件,需自行判断并调用回调:
立即学习“Java免费学习笔记(深入)”;
- 在动画循环中检测是否到达目标值或达到最大帧数
- 满足结束条件时,不再调用
requestAnimationFrame,并立即执行回调函数 - 注意清除可能存在的定时器或监听器,避免内存泄漏
function animate(current, target, duration, callback) {
const start = performance.now();
function step(now) {
const elapsed = now - start;
const progress = Math.min(elapsed / duration, 1);
const value = easeOutCubic(progress, current, target - current);
<pre class="brush:php;toolbar:false;">el.style.transform = `translateX(${value}px)`;
if (progress < 1) {
requestAnimationFrame(step);
} else {
callback?.(); // 动画真正结束时调用
}} requestAnimationFrame(step); }
注意事项与常见坑
实际开发中容易忽略以下细节:
- 动画未触发时(如元素初始 display: none 或动画名写错),
animationend永远不会触发 —— 可加超时兜底 - CSS 中设置了
animation-fill-mode: forwards不影响事件触发时机,但会影响结束后的样式状态 - 动态添加动画类后,需确保 DOM 已重排(如用
offsetHeight强制触发),否则动画可能不启动 - 移动端 WebKit 内核曾有
animationend不触发的 bug,必要时可结合setTimeout做降级处理

















