TransitionEnd 和 AnimationEnd 是分别监听 CSS 过渡与动画结束的原生事件;transitionend 仅在 transition 属性引发样式变化时触发,animationend 则在 @keyframes 动画播放完成时触发,二者不可混用,且需注意多属性触发、前缀兼容及重复绑定问题。
transitionend 和 animationend 是浏览器提供的原生事件,分别用于监听 css 过渡(transition)和 动画(animation)的结束。它们不是“执行完就自动触发一次”,而是每次动画/过渡完成都会触发——包括正向、反向、中断后恢复等场景,需注意重复触发和兼容性问题。
区分 TransitionEnd 与 AnimationEnd 的触发时机
两者本质不同,不能混用:
-
transitionend:只响应
transition属性定义的样式渐变(如opacity 0.3s、transform 0.2s ease-in),且仅在“有变化”的情况下触发(比如从opacity: 0→1,但若起止值相同则不触发)。 -
animationend:响应
@keyframes定义的完整动画序列(如slide-in),只要动画播放完成(无论是否循环、是否 fill-mode),就会触发;但若动画被animation-play-state: paused暂停,或未实际播放(如animation-duration: 0s),则不会触发。
正确绑定事件并防止重复触发
直接写 el.addEventListener('transitionend', handler) 很容易在连续操作中多次绑定,或因多属性过渡(如同时改 transform 和 opacity)导致同一动画触发多次事件。推荐做法:
- 使用
once: true选项确保只响应一次:el.addEventListener('transitionend', handler, { once: true }); - 在 handler 中通过
event.propertyName过滤关心的属性(如只处理transform):if (event.propertyName === 'transform') { /* 执行逻辑 */ } - 对 animationend,可用
event.animationName区分不同动画:if (event.animationName === 'fade-out') { /* 清理 DOM */ }
处理浏览器前缀与兼容性
旧版 Safari、Chrome(getAnimationEventName() 动态检测:
(可复用的工具函数)
function getTransitionEventName() {
const el = document.createElement('div');
const transitions = {
'transition': 'transitionend',
'OTransition': 'oTransitionEnd',
'MozTransition': 'transitionend',
'WebkitTransition': 'webkitTransitionEnd'
};
for (let t in transitions) {
if (el.style[t] !== undefined) return transitions[t];
}
return 'transitionend';
}
<p>function getAnimationEventName() {
const el = document.createElement('div');
const animations = {
'animation': 'animationend',
'OAnimation': 'oAnimationEnd',
'MozAnimation': 'animationend',
'WebkitAnimation': 'webkitAnimationEnd'
};
for (let a in animations) {
if (el.style[a] !== undefined) return animations[a];
}
return 'animationend';
}
</p>
之后统一用 el.addEventListener(getTransitionEventName(), ...) 即可适配主流环境。
常见陷阱与应对建议
-
过渡未触发?检查是否真有样式变化(例如 class 切换后,新 class 的 transition 属性是否生效)、是否被
display: none阻断(它会跳过 transition)、或是否在元素未挂载时就设置了样式。 - 事件没执行?确认监听的是目标元素(不是父级),且事件绑定在动画开始之前(不能等 class 加完再绑)。
-
需要精确控制时长?不要依赖事件时间戳做计算,优先用 CSS 的
animation-duration/transition-duration值,再结合 JS 控制流程。 -
Vue/React 等框架中?确保在 DOM 更新后(如
nextTick或useEffect的 layout effect 阶段)再添加监听,避免因异步渲染导致绑定时机错误。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











