CSS3 动画 - 使用过渡时不会触发 animationstart 事件:

CSS3 animations - animationstart event won't fire when using transition:

鉴于以下情况:

.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

是否有等效的东西?

以下代码有效。尽管您已为侦听器指定了 animationstart ,但您还在 css 中将动画定义为无限,这将导致警报仅在 first 初始开始时触发环形 。如果您想在每个 stop/start/repeat 周期检测动画:一种选择是使用 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)

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>

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

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

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

$('.transitioned').bind('transitionend', function() {
  console.log('Transition Ended');
});
.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%);
}
<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>


长答案:

首先,animationtransition 并不相同,尽管它们会逐渐改变分配给属性的值。以下是一些主要区别:

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

您可以在 this article.

中阅读更多关于它们之间的差异以及何时应该使用它们的信息

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

As per W3C Spec

Any animation for which both a valid keyframe rule and a non-zero duration are defined will run and generate events; this includes animations with empty keyframe rules.


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

我不能确定不执行 transitionstart 事件是有意识的决定,还是只是一个失误。但事实是我们目前没有同等的。

就我个人而言,我不认为这是一个很大的失误,因为开发人员应该知道 transition 的确切触发点(比如通过 JS 或通过用户交互添加新的 class也可以通过 JS 检测到的事件)。因此,我们总是可以说转换在满足触发条件的同一时刻开始。对于您的情况, transition 在执行 .addClass('slide') 的同时开始。所以,无论你想做什么额外的步骤(或)你想调用的函数都可以在 .addClass('slide') 执行后直接调用。

注意事项:

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

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>