Javascript 我可以使用JS等待多个CSS动画吗?
我们可以使用JS检测动画何时结束:Javascript 我可以使用JS等待多个CSS动画吗?,javascript,jquery,css,css-animations,Javascript,Jquery,Css,Css Animations,我们可以使用JS检测动画何时结束: const元素=$(“#可设置动画”); element.addClass('being-animated')。在(“animationend”,(事件)=>{ log('动画结束!'); }); @关键帧动画能力{ 0% { 不透明度:1; } 100% { 不透明度:0; } } @关键帧动画置换{ 0% { 变换:translate3d(0,0,0); } 100% { 转换:translate3d(0,15px,0); } } #动画化{ 动画:An
const元素=$(“#可设置动画”);
element.addClass('being-animated')。在(“animationend”,(事件)=>{
log('动画结束!');
});代码>
@关键帧动画能力{
0% {
不透明度:1;
}
100% {
不透明度:0;
}
}
@关键帧动画置换{
0% {
变换:translate3d(0,0,0);
}
100% {
转换:translate3d(0,15px,0);
}
}
#动画化{
动画:AnimatePocity 1s向前缓0s,animatePosition 2s向前缓0s;
}
我可能是被激活了。
第一个技巧:
向元素添加一个类,然后处理每个动画并等待它们结束,不管发生什么。这是按类触发动画的常用方法
根据Kaido的评论并指出,这将等待每一个动画,无论需要多长时间才能完成。这就是所有这些背后的动机:创建一个漂亮的动画,让JS意识到它(无论多么复杂/漫长)完成它,这样你就可以链接其他东西
如果你不这样做,你可能会有一个很好的动画运行,突然被其他东西切断…这是糟糕的
const triggerAnimationWithClass = (classToAdd, toWhat) => {
const element = document.querySelector(toWhat);
/**
* Initialize the count with 1, because you'll always have at least one animation no matter what.
*/
let animationCount = 1;
return new Promise((resolve, reject) => {
element.addEventListener('animationend', (event) => {
if((window.getComputedStyle(element).animationName).split(',').length - animationCount === 0) {
/**
* Remove the current function being hooked once we're done. When a class gets added that contains any N number of animations,
* we're running in a synchronous environment. There is virtually no way for another animation to happen at this point, so, we're
* surgically looking at animations that only happen when our classToAdd gets applied then hooking off to not create conflicts.
*/
element.removeEventListener('animationend', this);
const animationsDonePackage = {
'animatedWithClass': classToAdd,
'animatedElement': toWhat,
'animatedDoneTime': new Date().getTime()
};
resolve(animationsDonePackage);
} else {
animationCount++;
}
});
element.classList.add(classToAdd);
});
}
这将处理添加的多个类。让我们假设,从外部来看,有人在您添加自己的类的同时添加了另一个类(奇怪,但是,让我们假设它发生了)。然后将该元素上的所有动画视为一个,函数将等待所有动画完成
第二种技巧:
基于@B-Dawg的回答。处理一组动画,基于名称(CSS动画名称),而不是类,请阅读后面的单词:
const onAnimationsComplete = ({element, animationsToLookFor}) => {
const animationsMap = new WeakMap();
if(!animationsMap.has(element)) {
const animationsCompleted = {};
for(const animation of animationsToLookFor) {
animationsCompleted[animation] = false;
}
animationsMap.set(element, animationsCompleted);
}
return new Promise((resolve, reject) => {
// When any animation completes...
element.addEventListener('animationend', ({target, animationName, elapsedTime}) => {
const animationsCompleted = animationsMap.get(target);
animationsCompleted[animationName] = true;
// If every animation is now completed...
if(Object.values(animationsCompleted).every(isCompleted => isCompleted === true)) {
const animations = Object.keys(animationsCompleted);
// Reset for next time - set all animations to not complete (false)
animations.forEach(animation => animationsCompleted[animation] = false);
//Remove the listener once we're done.
element.removeEventListener('animationend', this);
resolve({
'animationsDone': animationsToLookFor
});
}
});
});
};
这有一个bug。假设一个新的动画来自(比如)一个新的类,如果它没有被放入animationsToLookFor
列表中,这永远不会解决
试图修复它,但如果我们谈论的是您正在寻找的动画的精确列表,则这是第一个技术:
向元素添加一个类,然后处理每个动画并等待它们结束,不管发生什么。这是按类触发动画的常用方法
根据Kaido的评论并指出,这将等待每一个动画,无论需要多长时间才能完成。这就是所有这些背后的动机:创建一个漂亮的动画,让JS意识到它(无论多么复杂/漫长)完成它,这样你就可以链接其他东西
如果你不这样做,你可能会有一个很好的动画运行,突然被其他东西切断…这是糟糕的
const triggerAnimationWithClass = (classToAdd, toWhat) => {
const element = document.querySelector(toWhat);
/**
* Initialize the count with 1, because you'll always have at least one animation no matter what.
*/
let animationCount = 1;
return new Promise((resolve, reject) => {
element.addEventListener('animationend', (event) => {
if((window.getComputedStyle(element).animationName).split(',').length - animationCount === 0) {
/**
* Remove the current function being hooked once we're done. When a class gets added that contains any N number of animations,
* we're running in a synchronous environment. There is virtually no way for another animation to happen at this point, so, we're
* surgically looking at animations that only happen when our classToAdd gets applied then hooking off to not create conflicts.
*/
element.removeEventListener('animationend', this);
const animationsDonePackage = {
'animatedWithClass': classToAdd,
'animatedElement': toWhat,
'animatedDoneTime': new Date().getTime()
};
resolve(animationsDonePackage);
} else {
animationCount++;
}
});
element.classList.add(classToAdd);
});
}
这将处理添加的多个类。让我们假设,从外部来看,有人在您添加自己的类的同时添加了另一个类(奇怪,但是,让我们假设它发生了)。然后将该元素上的所有动画视为一个,函数将等待所有动画完成
第二种技巧:
基于@B-Dawg的回答。处理一组动画,基于名称(CSS动画名称),而不是类,请阅读后面的单词:
const onAnimationsComplete = ({element, animationsToLookFor}) => {
const animationsMap = new WeakMap();
if(!animationsMap.has(element)) {
const animationsCompleted = {};
for(const animation of animationsToLookFor) {
animationsCompleted[animation] = false;
}
animationsMap.set(element, animationsCompleted);
}
return new Promise((resolve, reject) => {
// When any animation completes...
element.addEventListener('animationend', ({target, animationName, elapsedTime}) => {
const animationsCompleted = animationsMap.get(target);
animationsCompleted[animationName] = true;
// If every animation is now completed...
if(Object.values(animationsCompleted).every(isCompleted => isCompleted === true)) {
const animations = Object.keys(animationsCompleted);
// Reset for next time - set all animations to not complete (false)
animations.forEach(animation => animationsCompleted[animation] = false);
//Remove the listener once we're done.
element.removeEventListener('animationend', this);
resolve({
'animationsDone': animationsToLookFor
});
}
});
});
};
这有一个bug。假设一个新的动画来自(比如)一个新的类,如果它没有被放入animationsToLookFor
列表中,这永远不会解决
试图修复它,但如果我们谈论的是您正在寻找的动画的精确列表,那么这就是我们的目标。免责声明:我认为jQuery对于回答这个问题并不重要,如果其他人在看到这个答案后选择依赖此代码,则会损害负载和运行时性能。因此,我将使用香草JavaScript来回答,以帮助尽可能多的人,但是如果您想使用jQuery,您仍然可以应用相同的概念
回答:没有动画队列,但您可以自己制作。
例如,可以使用闭包和/或a(在下面的代码段中,我实际上使用了a)将有关动画的数据链接到目标元素,以帮助垃圾收集。如果在动画状态完成后将其保存为true
,则可以检查并最终在所有状态均为true
时触发不同的回调,或者发送自己的自定义事件。我使用了自定义事件方法,因为它更灵活(能够添加多个回调)
下面的代码还可以帮助您避免在实际只关心几个特定动画的情况下等待所有动画。它还应该允许您多次处理多个单独元素的动画事件(尝试运行代码段并单击框几次)
const addAnimationEndAllEvent=(()=>{
const weakMap=new weakMap()
const initanimationobject=(元素、预期动画、事件名称)=>{
const events=weakMap.get(元素)
常量animationsCompleted={}
for(预期动画的常量动画){
animationsCompleted[动画]=假
}
事件[eventName]=动画已完成
}
return(元素,预期动画,eventName='animationendall')=>{
如果(!weakMap.has(element))weakMap.set(element,{})
如果(预期寿命){
InitAnimationObject(元素、预期动画、事件名称)
}
//当任何动画完成时。。。
element.addEventListener('animationend',({target,animationName})=>{
const events=weakMap.get(目标)
//如果之前没有提供任何动画,请使用所有动画
如果(!事件[eventName]){
InitAnimationObject(目标,window.getComputedStyle(目标).animationName.split(','),eventName)
}
const animationsCompleted=事件[eventName]
//确保跟踪此动画
如果(!(animationsCompleted中的animationName))返回
//将当前动画标记为完成(true)
animationsCompleted[animationName]=真
//如果现在每个动画都完成了。。。
如果(对象)