用 Promise 封装 CSS 动画结束事件,核心是监听 animationend(或 webkitAnimationEnd)并返回 Promise,配合 element.style.animation 动态触发,就能实现“动画一完就继续执行”的丝滑控制。

用 Promise 封装 CSS 动画结束事件,核心是监听 animationend(或 webkitAnimationEnd)并返回 Promise,配合 element.style.animation 动态触发,就能实现“动画一完就继续执行”的丝滑控制。
监听动画结束并返回 Promise
直接监听单次动画的结束时机,避免手动清理事件监听器:
function waitForAnimation(el) {
return new Promise(resolve => {
const handleEnd = () => {
el.removeEventListener('animationend', handleEnd);
el.removeEventListener('webkitAnimationEnd', handleEnd);
resolve();
};
el.addEventListener('animationend', handleEnd);
el.addEventListener('webkitAnimationEnd', handleEnd);
});
}
注意:必须同时监听 webkitAnimationEnd 兼容 Safari;监听后立即移除,防止重复触发。
动态添加动画类并等待完成
封装成可复用函数,支持传入动画类名、可选持续时间(用于 fallback 超时兜底):
立即学习“Java免费学习笔记(深入)”;
async function animateOnce(el, className, timeoutMs = 500) {
el.classList.add(className);
try {
await Promise.race([
waitForAnimation(el),
new Promise(resolve => setTimeout(resolve, timeoutMs))
]);
} finally {
el.classList.remove(className);
}
}
使用示例:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
// 触发 slide-in 动画,完成后执行后续逻辑
await animateOnce(myElement, 'slide-in');
console.log('动画已结束,DOM 已就绪');
加 Promise.race 是为防动画被中途取消、CSS 类未生效等异常场景,避免 Promise 永远不 resolve。
配合 transition 实现更自然的过渡
对 transition 类型变化(如 opacity、transform),监听 transitionend 同理:
function waitForTransition(el) {
return new Promise(resolve => {
const handleEnd = () => {
el.removeEventListener('transitionend', handleEnd);
resolve();
};
el.addEventListener('transitionend', handleEnd);
});
}
// 使用时先设置样式,再触发重排,让 transition 生效
function animateTransition(el, styles) {
// 强制重排,确保浏览器记录初始状态
void el.offsetHeight;
Object.assign(el.style, styles);
return waitForTransition(el);
}
关键点:void el.offsetHeight 触发同步布局,让 transition 从当前状态开始计算。
组合多个动画步骤(串行 & 并行)
利用 await 串联动画,或 Promise.all 并行控制多个元素:
- 串行:依次播放入场 → 内容更新 → 出场
- 并行:多个卡片同时淡入,统一等待全部结束
- 可封装成
animateSequence([step1, step2])或animateAll([el1, el2], 'fade-in')
例如并行淡入:
await Promise.all(
[box1, box2, box3].map(el => animateOnce(el, 'fade-in'))
);
console.log('所有元素淡入完成');
不复杂但容易忽略细节:每个动画需有唯一 class、避免 class 冲突;动画属性(如 animation-fill-mode: forwards)决定结束后是否保留终态,按需设置。

















