JavaScript中如何检测动画是否结束
在前端开发中,我们经常会遇到需要监听动画结束的场景,比如动画播放完成后执行后续逻辑、移除动画相关样式或者触发新的交互效果。JavaScript提供了原生的动画结束事件,能够帮助我们精准捕获动画的完成时机,下面我们就来详细介绍具体的实现方法。
监听CSS动画结束事件
如果是通过CSS的animation属性定义的动画,我们可以监听animationend事件来检测动画是否结束。这个事件会在CSS动画完成一个迭代周期后触发,如果动画设置了animation-iteration-count: infinite无限循环,那么animationend事件不会触发。
需要注意的是,不同浏览器内核曾经有私有前缀的事件名,比如WebKit内核的webkitAnimationEnd,不过现在主流现代浏览器都已经支持标准的animationend事件,为了兼容性考虑,我们也可以同时监听带前缀的事件作为兜底。
下面是一个简单的示例,我们先定义一个CSS动画,然后通过JavaScript监听动画结束事件:
/* 定义CSS动画 */
.box {
width: 100px;
height: 100px;
background-color: #409eff;
/* 动画名为fadeOut,持续1秒,结束保持最后一帧状态 */
animation: fadeOut 1s forwards;
}
@keyframes fadeOut {
from {
opacity: 1;
transform: translateX(0);
}
to {
opacity: 0;
transform: translateX(100px);
}
}对应的HTML结构和JavaScript监听逻辑如下:
// 获取动画元素
const box = document.querySelector('.box');
// 定义动画结束的回调函数
function handleAnimationEnd(e) {
console.log('CSS动画已结束,动画名称:', e.animationName);
// 可以在这里执行动画结束后的逻辑,比如移除元素
// box.remove();
}
// 监听标准animationend事件
box.addEventListener('animationend', handleAnimationEnd);
// 兼容旧版本WebKit内核浏览器,监听webkitAnimationEnd事件
box.addEventListener('webkitAnimationEnd', handleAnimationEnd);
// 如果有多个动画,可以通过e.animationName判断是哪个动画结束animationend事件的事件对象中包含很多有用的属性,比如animationName可以获取结束的动画名称,elapsedTime可以获取动画已经运行的秒数,方便我们在有多个动画的场景下做区分处理。
监听CSS过渡结束事件
如果使用的是CSS的transition属性实现的过渡效果,对应的结束事件是transitionend,它的使用方式和animationend类似。同样,旧版本浏览器可能有webkitTransitionEnd的前缀事件,我们可以一并监听保证兼容性。
下面是一个过渡效果的示例:
/* 定义过渡效果 */
.transition-box {
width: 100px;
height: 100px;
background-color: #67c23a;
transition: width 0.5s ease, background-color 0.5s ease;
}
/* 触发过渡的类 */
.transition-box.active {
width: 200px;
background-color: #e6a23c;
}对应的JavaScript监听逻辑:
const transitionBox = document.querySelector('.transition-box');
function handleTransitionEnd(e) {
console.log('过渡效果结束,过渡属性:', e.propertyName);
// 可以执行后续逻辑
}
// 监听标准transitionend事件
transitionBox.addEventListener('transitionend', handleTransitionEnd);
// 兼容旧版本WebKit内核浏览器
transitionBox.addEventListener('webkitTransitionEnd', handleTransitionEnd);
// 点击元素触发过渡
transitionBox.addEventListener('click', () => {
transitionBox.classList.toggle('active');
});需要注意的是,如果一个元素同时有多个属性发生过渡,transitionend事件会为每个发生过渡的属性都触发一次,我们可以通过事件对象的propertyName属性判断是哪个属性的过渡结束。
检测Web Animations API动画结束
除了CSS动画和过渡,我们还可以使用Web Animations API通过JavaScript直接创建和控制动画,这种方式的动画结束检测更加直观,因为动画对象本身提供了finished Promise属性,我们可以通过这个Promise来捕获动画结束的时机。
下面是一个Web Animations API的示例:
const animateBox = document.querySelector('.animate-box');
// 使用Web Animations API创建动画
const animation = animateBox.animate([
{ opacity: 1, transform: 'scale(1)' },
{ opacity: 0.5, transform: 'scale(1.2)' },
{ opacity: 1, transform: 'scale(1)' }
], {
duration: 800, // 动画持续800毫秒
easing: 'ease-in-out',
iterations: 1 // 只播放一次
});
// 通过finished Promise监听动画结束
animation.finished.then(() => {
console.log('Web Animations API动画已结束');
// 执行后续逻辑
}).catch((err) => {
// 如果动画被取消,会进入catch回调
console.log('动画被取消:', err);
});
// 也可以通过onfinish回调监听
animation.onfinish = () => {
console.log('通过onfinish回调检测到动画结束');
};Web Animations API的finished Promise会在动画正常播放完成时被resolve,如果动画被cancel()方法取消,那么Promise会被reject,我们可以根据实际需求选择使用Promise方式还是回调方式。
注意事项
- 如果动画设置了无限循环,那么
animationend和transitionend事件都不会触发,需要手动在动画逻辑中处理循环结束的条件。 - 监听事件后,如果元素被移除或者不需要再监听事件,记得通过
removeEventListener移除对应的事件监听,避免内存泄漏。 - 当同时存在多个动画时,建议通过事件对象的属性区分不同的动画,避免逻辑混淆。
- Web Animations API的兼容性目前现代浏览器都已经支持,如果需要在非常旧的浏览器中使用,需要提前确认兼容性或者引入对应的polyfill。
JavaScript动画结束检测animationend事件transitionend事件Web Animations API动画监听