У меня есть следующий код, и моя проблема в том, что событие transitionend запускается дважды. Я не знаю, что вызывает это. Я подозревал, что причиной этого стали префиксы поставщиков, но это не так. Даже если я оставлю только transitionend и transition он все равно сработает дважды.

CSS

 transition: 1s ease-out; 

JS

 document.addEventListener('click', function (e) { var submarine = document.querySelector('.submarine'); var submarineX = e.clientX - submarine.offsetWidth / 2; var submarineY = e.clientY - submarine.offsetHeight / 2; submarine.style.left = submarineX   "px"; submarine.style.top = submarineY   "px"; }); document.addEventListener('transitionend', function (event) { console.log(event.type   " "   new Date().getTime()); }); 

скрипка

 document.addEventListener('transitionend', function (event) { console.log(event.type   " "   new Date().getTime()); }); document.addEventListener('click', function (e) { var submarine = document.querySelector('.submarine'); var submarineX = e.clientX - submarine.offsetWidth / 2; var submarineY = e.clientY - submarine.offsetHeight / 2; submarine.style.left = submarineX   "px"; submarine.style.top = submarineY   "px"; }); 
 .submarine { position: absolute; top: 0; left: 0; width: 20px; height: 20px; background-color: red; border-radius: 50%; transition: 1s ease-out; } 
 {amp}lt;div class="submarine"{amp}gt;{amp}lt;/div{amp}gt; 

transitionend запускает для каждого свойства, в вашем случае top и left .

Вы можете получить доступ к свойству, связанному с событием, по адресу event.propertyName .

Нет никакого события «end s transition», так что вам, вероятно, понадобится некоторая хакерская способность, такая как фильтрация обработки обратного вызова transitionend только для одного из переходных свойств. Например:

 function (event) { if (event.propertyName == 'top') { //put your code here } }); 

пс. Ни один браузер не запускает событие MSTransitionEnd . Это было в какой-то момент в документах MS, но когда-то перед бета-версией IE10 его заменило стандартное событие transitionend .

Событие запускается для каждого свойства, которое было передано.

Способ propertyName , предложенный Fabricio, является правильным способом сделать это, однако, в зависимости от обстоятельств, вы также можете использовать one(); а так вот так.

 $(document).one('transitionend webkitTransitionEnd MSTransitionEnd', function() { ... }); 

Для тех, кто ищет простое, одноразовое решение для копирования и вставки (я включил только необходимые CSS). Это не отвечает на вопрос, и это действительно отвечает на то, что я искал, когда я приземлился здесь.

CSS:

 .my-elem { transition: height 0.5s ease-out, opacity 0.5s ease-out; } 

JavaScript:

 var elem = document.querySelector(".my-elem"); var transitionCounter = 0; var transitionProp = window.getComputedStyle(elem , null)["transition-property"] || ""; // We just need to know how many transitions there are var numTransitionProps = transitionProp.split(",").length; elem.addEventListener("transitionend", (event) ={amp}gt; { // You could read event.propertyName to find out which transition was ended, // but it's not necessary if you just want to know when they are all done. if (transitionCounter {amp}lt; (numTransitionProps - 1)) { transitionCounter  ; } else { transitionCounter = 0; // reset alert("I'm done!!!"); // do what you need to } }, false); 

Протестировано в IE11, Chrome 48 и Firefox 37.

Для тех, кто все еще ищет более надежное решение, такое как событие «allTransitionEnd», я реализовал «специальное событие» jQuery , скорее как подтверждение концепции того, над чем я работал, но я мог бы выпустить lib на Github.

Проверьте JSBin .

Это довольно сложно, так что я не буду объяснять слишком много, но это действительно облегчает выполнение вещей после ВСЕХ переходов на элементе:

 $(function () { $element.on('allTransitionEnd', function () { // do something after all transitions end. }); }); 

Он работает, проверяя элемент на предмет свойств перехода, а затем связывается с собственными событиями transitionend (в том числе от поставщика), чтобы отслеживать свойства, которые завершили переход. Когда все завершают переход, он запускает любые связанные обработчики allTransitionsEnd а затем очищает свойства перехода, если они тоже изменились, и allTransitionsEnd следующий раз.

Это действительно полезно, когда несколько свойств переходятся с различной задержкой и / или продолжительностью, и вы хотите что-то сделать после завершения всех переходов.

Примеры использования:

  • Удалите мгновенное сообщение после исчезновения и уменьшите.
  • Инициирование «открытых» и «закрытых» событий в повторно используемом компоненте, таком как меню или модальный режим, где потребители могут захотеть выполнить некоторую логику после завершения перехода, не выискивая переходы CSS.

Если вы переходите только в одно свойство или у вас нет различных задержек и / или длительностей, тогда простое решение работает отлично.

Работает в последних версиях Chrome, Firefox, Safari, Mobile Safari и IE11 и IE10. Не работает в IE8, потому что переходы не поддерживаются. Привязка к дополнительному нативному событию в качестве резервного.

Вы можете использовать target свойство, чтобы отфильтровать события, которые запускаются дочерними элементами, и использовать propertyName чтобы инициировать событие только при изменении определенного свойства.

 const handleTransitionEnd = event ={amp}gt; { if (event.target !== myDomElementRef) return; if (event.propertyName !== "height") return; // Do my things }; 

Это довольно старый вопрос, но я решил поделиться своим ответом:

 function OnTransitionEvent() { var t, el = document.createElement('transitionElement'); var transitions = { 'transition' : 'transitionend', 'OTransition' : 'oTransitionEnd', 'MozTransition' : 'transitionend', 'WebkitTransition': 'webkitTransitionEnd' }; for (t in transitions){ if (el.style[t] !== undefined){ return transitions[t]; } } } var transitionEvent = OnTransitionEvent(); $(document).one(transitionEvent, function() { console.log('done'); });