Переходное событие срабатывает дважды
У меня есть следующий код, и моя проблема в том, что событие 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());
});
Fiddle
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;
}
<div class="submarine"></div>
Ответы
Ответ 1
transitionend
срабатывает для каждого свойства, перенесенного в вашем случае top
и left
.
Вы можете получить доступ к свойству, связанному с событием, в event.propertyName
.
Нет события "переход s end", поэтому вам, вероятно, понадобится хакерство, например, фильтрация обработки обратного вызова transitionend
только для одного из перешедших свойств. Например:.
function (event) {
if (event.propertyName == 'top') {
//put your code here
}
});
пс. Ни один браузер не запускает событие MSTransitionEnd
. Это было в какой-то момент в документах MS, но когда-то до бета-версии IE10 он был заменен стандартным событием transitionend
.
Ответ 2
Событие запускается для каждого свойства, которое было перенесено.
Способ propertyName
, предложенный Fabricio, является правильным способом сделать это, однако в зависимости от обстоятельств вы также можете использовать one();
, как это.
$(document).one('transitionend webkitTransitionEnd MSTransitionEnd', function() {
...
});
Ответ 3
Для тех, кто ищет простое одноразовое решение для копирования и вставки (я включил только необходимый 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) => {
// You could read event.propertyName to find out which transition was ended,
// but it not necessary if you just want to know when they are all done.
if (transitionCounter < (numTransitionProps - 1)) {
transitionCounter++;
} else {
transitionCounter = 0; // reset
alert("I'm done!!!"); // do what you need to
}
}, false);
Протестировано в IE11, Chrome 48 и Firefox 37.
Ответ 4
Для тех, кто все еще ищет более надежное решение, например событие "allTransitionEnd", я внедрил jQuery "специальное событие" , подробнее как доказательство концепции для чего-то, над чем я работал, но я мог бы выпустить lib на Github.
Посмотрите JSBin.
Это довольно сложно, поэтому я не буду объяснять слишком много, но это делает его очень легким, чтобы делать вещи после того, как все переходы закончились на элементе:
$(function () {
$element.on('allTransitionEnd', function () {
// do something after all transitions end.
});
});
Он работает, исследуя элемент для свойств перехода, затем привязывается к нативным событиям transitionend
(включая специфику поставщика), чтобы отслеживать свойства, которые завершили переход. Когда все закончили переход, он запускает любые связанные обработчики allTransitionsEnd
, а затем очищает свойства перехода, в случае их изменения, а также зонды для них в следующий раз.
Это действительно полезно, когда несколько свойств переходят с переменной задержкой и/или продолжительностью, и вы хотите что-то сделать после завершения всех переходов.
Примеры использования:
- Удалите флэш-сообщение после исчезновения и сжатия.
- Запускать "открытые" и "закрытые" события в компоненте многократного использования, таком как меню или модальный, где потребители могут захотеть выполнить некоторую логику после завершения перехода, не вдаваясь в css-переходы.
Если вы только переходите к одному свойству или не имеете разных задержек и/или продолжительности, то простое решение прекрасно работает.
Работает в последней версии Chrome, Firefox, Safari, Mobile Safari и IE11 и IE10. Не работает в IE8, потому что переходы не поддерживаются. Привяжите к дополнительному родному событию как резерв.
Ответ 5
Это относительно старый вопрос, но я решил поделиться своим ответом:
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');
});