CSS3动画 - 使用转换时不会触发animationstart事件:

时间:2015-12-15 18:24:55

标签: javascript css css3 css-transitions css-animations

鉴于以下内容:

.slide{
  transition: all 1s ease 0s;
  transform: translateX(-100%);
}

document.documentElement.addEventListener('animationstart', function() {
  alert(1);
}, false); 

事件不会发生。

但是,如果CSS是:

.slide {
  animation: slide 1s infinite
}

@keyframes slide {
  from {
    transform: translateX(0);
  }
  to { 
    transform: translateX(-100px);
   }
}

它会解雇。

为什么?在这两种情况下都是动画,但是,在第一种情况下,我们不使用具有其他负面后果的关键帧。

这不是浏览器如何实现此功能的错误吗?

以下是第一个示例:

http://jsbin.com/hizoyopimu/1/edit?html,css,js,console,output

第二名:

http://jsbin.com/yegidehusi/1/edit?html,css,js,console,output

有没有相应的东西?

3 个答案:

答案 0 :(得分:10)

TL; DR(简答):

截至目前,没有任何事件在转换开始时被触发。转换总是仅在满足触发条件时发生,因此触发转换的事件可以大致被视为等同于transitionstart事件。

在下面的代码段中,我添加了一个用户定义的函数(transitionStart),该函数在.addClass('slide')之后立即调用,这相当于transitionstart



/* For Animation Start */
setTimeout(function() {
  $('.animated').removeClass('hide').addClass('slide');
}, 1000);

$('.animated').bind('animationstart webkitAnimationStart', function() {
  console.log('Animation Started');
});

/* For Transition Start */
setTimeout(function() {
  $('.animated').removeClass('hide').addClass('slide');
  transitionStart();
}, 1000);

function transitionStart(){
  console.log('Transition Started');
}

.element {
  padding: 10px;
  background-color: #ccc;
  width: 100px;
  height: 100px;
}
.element.animated.hide {
  display: none;
}
.animated.slide {
  animation: slide 1s infinite
}
@keyframes slide {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-100px);
  }
}
.element.transitioned.hide {
  transform: translateX(-100%);
}
.transitioned.slide {
  transition: all 2s ease-in 0s;
  transform: translateX(200%);
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<h3>Element with Animation</h3>
<div class='element hide animated'>
  box
</div>

<h3>Element with Transition</h3>
<div class='element hide transitioned'>
  box
</div>
&#13;
&#13;
&#13;

transitionend事件可用,可用于标识转换的结束点,然后执行任何所需的函数调用或其他过程。下面的代码段有一个示例。

&#13;
&#13;
setTimeout(function() {
  $('.transitioned').removeClass('hide').addClass('slide');
  transitionStart();
}, 1000);

function transitionStart(){
  console.log('Transition Started');
}

$('.transitioned').bind('transitionend', function() {
  console.log('Transition Ended');
});
&#13;
.element {
  padding: 10px;
  background-color: #ccc;
  width: 100px;
  height: 100px;
}
.element.transitioned.hide {
  transform: translateX(-100%);
}
.transitioned.slide {
  transition: all 2s ease-in 0s;
  transform: translateX(200%);
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<h3>Element with Transition</h3>
<div class='element hide transitioned'>
  box
</div>
&#13;
&#13;
&#13;

长答案:

首先,animationtransition不相同,即使它们会逐渐更改分配给属性的值。以下是一些主要差异:

  • 转换只能有一个开始状态和一个结束状态。中间状态超出了开发人员的控制范围,由UA决定。使用动画时,开发人员可以根据需要在开始和结束状态之间指定任意数量的中间状态。
  • 与动画不同,无法自动启动/触发过渡。仅当通过用户交互(例如hoverclick等)或通过JS向元素添加一些额外类时,才会启动转换。加载页面时,动画可以自动启动。
  • 转换没有循环或迭代(与动画不同)。转换只能运行一次。

您可以详细了解它们之间的差异以及何时应在this article中使用它。

Animation eventsanimationstartanimationend等)不会针对您的第一个案例(使用transition的情况)触发,因为没有animation在元素上指定的有效@keyframe规则。

  

根据W3C Spec

     

定义了有效关键帧规则和非零持续时间的任何动画都将运行并生成事件;这包括具有空关键帧规则的动画。

根据当前规范,与transition启动时不同,启动animation时不会触发特定事件。换句话说,没有transitionstart事件。目前只实现了一个转换事件(transitionend)。 (W3C Spec)。

我无法确定是否有意识地决定不执行transitionstart事件,或者只是一次失败。但事实是,我们目前没有相同的产品。

就个人而言,我并不认为这是一个很大的错过,因为开发人员应该知道transition的确切触发点(比如通过JS添加新类或通过用户交互事件也可以检测到通过JS)。因此,我们总是可以说转换已经在满足触发条件的同一时刻开始。对于您的情况,transition已在.addClass('slide')执行的同时启动。因此,在执行.addClass('slide')之后,可以直接调用要执行的任何额外步骤(或)要调用的函数。

注意事项:

  • 上述查找转换启动的方式并非100%等同于animationstart事件。原因是因为animationstart事件仅在设置的animation-delay到期后才会触发。在您的代码段中,动画或转换都没有延迟,因此这不是一个大问题。如果确实有延迟,那么您必须获取transition-delay属性的值并在调用所需的函数(或)操作之前执行另一个超时。
  • 我记得早些时候在另一篇文章中读到IE10有transitionstart事件,但它不符合标准,因此不推荐。

答案 1 :(得分:2)

现在是2020年:

使用过渡时,必须使用transition个事件而不是animation个事件。

Compatability table(甚至在Edge v42中也可以使用)

  yourElement.addEventListener("transitionstart", () => {
      alert("transitionstart");
  });

示例:

const div1 = document.querySelector(".div1");
  
  div1.addEventListener("click", () => {
      div1.classList.toggle("transition");
 });
 
  div1.addEventListener("transitionstart", () => {
      console.log("transitionstart");
    });
.div1{
  transition: transform 1s ease-in-out;
  background-color: darkseagreen;
  display:inline-block;
}

.div1.transition{
transform: translateX(100px);
}

.div1.transition:after{
content: " again, when transition stopps!";
  background-color: yellow;
}
<div class="div1"> CLICK ME</div>

答案 2 :(得分:1)

以下代码有效。虽然您已为侦听器指定了animationstart,但您还将css中的动画定义为无限,这将导致警报仅在无限循环的第一次初始启动时触发。如果你想在每个停止/开始/重复循环中检测动画:一个选项是使用javascript而不是无限的css循环动画。希望这有助于您的研究。

.slide {
        animation: slide 1s infinite
}

@keyframes slide {
        from {
                transform: translateX(0);
        }
        to { 
                transform: translateX(100px);
        }
}

JS

var x = document.querySelector('.slide');

x.addEventListener('animationstart',function(){
  alert(1)

},false)