关于切换CSS属性(即动画)的执行顺序的问题



在这个例子中,如果我没有嵌套

box.style。动画= 'myanimation 3s'

在setTimeout中,则代码不起作用。但是当我像这样运行它时,它的超时延迟为零,它工作了。最初我认为这可能是一个执行时间错误,所以我将Timeout delay设置为50,但我很好奇,尝试了更低的数值,直到达到零,它仍然运行。从本质上讲,我只是试图在每次点击元素时实现一个动画。是否有更好/更安全的解决方案?另外,出于好奇,直接在'if'语句之后运行这行代码与将其嵌套在延迟为0的setTimeout中有什么区别?我正在使用Ubuntu LTS 20.04的Firefox

编辑:我应该补充,如果我没有嵌套setTimeout函数,动画将运行第一次,但不是任何后续的时间。但是当我像所示的那样运行代码时,它每次都运行。输入图片描述

const box = document.querySelector('.box')
box.addEventListener('click', function() {
if(box.style.animation){
box.style.animation = ''
}
setTimeout(function() {
box.style.animation = 'myanimation 3s'
}, 0)

})
编辑:我在reddit上看到的另一个答案是监听一个animationend事件,比如:
const box = document.querySelector('.box')
box.addEventListener('click', function() {
box.style.animation = 'myanimation 3s'
})
box.addEventListener('animationend', function()  {
box.style.animation = ''
})

当你不使用超时时,看起来什么都没有发生的原因是现代浏览器完全优化了第一个语句,以防止不必要的操作发生,这会对性能产生负面影响。

浏览器注意到您将animation属性设置为空字符串,只是为了在下一行中将其设置为另一个值。这会导致回流,在很多情况下,这不是你想要的。在本例中,尝试重置CSS动画,这正是你想要的。

所以你需要告诉浏览器故意引起流。一种方法是使用setTimeout,所以第一个表达式不会被优化掉。另一种方法是通过做一些本身就会引起回流的事情来引起回流。offsetLeft,offsetTop,offsetWidthoffsetHeight是这样的属性,为了在访问它们时报告准确的值而引起回流。只需访问它们就足够了,而不需要将值放入变量或任何东西中:

const box = document.querySelector('.box')
box.addEventListener('click', function() {
if (box.style.animation) {
box.style.animation = ''
}
box.offsetLeft; // this forces a reflow, just like setTimeout
box.style.animation = 'myanimation 3s'
})
.box {
background: red;
width: 120px;
height: 120px;
position: relative;
}
.box::after {
content: "click me!";
color: #fff;
display: block;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%)
}
@keyframes myanimation {
from {
transform: translateY(0)
}
50% {
transform: translateY(1em)
}
to {
transform: translateY(0);
}
}
<div class="box">
</div>

最新更新