Обратный вызов при завершении перехода CSS3

202

Я хотел бы потушить элемент (изменив его непрозрачность на 0), а затем, когда закончите, удалить элемент из DOM.

В jQuery это просто, так как вы можете указать «Удалить», которое должно произойти после завершения анимации. Но если я хочу анимировать с помощью CSS3-переходов, есть ли способ узнать, когда переход / анимация завершены?

CJ
источник
3
должно быть похоже на это: stackoverflow.com/questions/6186454/…
Николас Модржик
5
Дубликат: stackoverflow.com/questions/2087510/callback-on-css-transition
Варун Сингх

Ответы:

334

Для переходов вы можете использовать следующее для определения конца перехода через jQuery:

$("#someSelector").bind("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){ ... });

У Mozilla есть отличная ссылка:

https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions#Detecting_the_start_and_completion_of_a_transition

Для анимации это очень похоже:

$("#someSelector").bind("animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd", function(){ ... });

Обратите внимание, что вы можете передавать все строки событий с префиксом браузера одновременно в метод bind (), чтобы поддерживать срабатывание события во всех браузерах, которые его поддерживают.

Обновить:

Согласно комментарию, оставленному Duck: вы используете .one()метод jQuery, чтобы обработчик срабатывал только один раз. Например:

$("#someSelector").one("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){ ... });

$("#someSelector").one("animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd", function(){ ... });

Обновление 2:

bind()Метод jQuery устарел, и on()метод является предпочтительным с jQuery 1.7.bind()

Вы также можете использовать off()метод в функции обратного вызова, чтобы обеспечить его запуск только один раз. Вот пример, который эквивалентен использованию one()метода:

$("#someSelector")
.on("animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd",
 function(e){
    // do something here
    $(this).off(e);
 });

Ссылки:

Джим Джефферс
источник
13
Стоит отметить, что обратный вызов будет запущен для каждого дочернего элемента, который также проходит. Это очень важно иметь в виду, если вам интересно, почему ваш обратный вызов срабатывает больше раз, чем вы ожидали. Я не знаю каких-либо обходных путей на данный момент.
Лев
22
@Lev, вы можете легко смягчить это, сравнивая currentTarget события с его целью. Так что-то вроде: function (event) {if (event.target === event.currentTarget) {/ * Делать вещи * /}}
Джим Джефферс
5
Да, я понял это вскоре после того, как написал комментарий. > _ <Спасибо за публикацию; Я уверен, что это поможет другим! :)
Лев
9
Мы используем , .on()а не .bind()для JQuery v1.7 + api.jquery.com/bind
ОЛО
4
Все современные браузеры теперь поддерживают событие без префикса. caniuse.com/#feat=css-transitions Также обратите внимание, что если у вас есть «transitionend webkitTransitionEnd», он будет запущен дважды в Chrome.
Майкл С.
17

Другой вариант - использовать jQuery Transit Framework для обработки ваших переходов CSS3. Переходы / эффекты хорошо работают на мобильных устройствах, и вам не нужно добавлять ни одной беспорядочной CSS3-переходы в ваш CSS-файл для создания анимационных эффектов.

Вот пример, при котором непрозрачность элемента будет изменена на 0 при нажатии на него, и будет удалена после завершения перехода:

$("#element").click( function () {
    $('#element').transition({ opacity: 0 }, function () { $(this).remove(); });
});

JS Fiddle Demo

ROFLwTIME
источник
Обратный вызов не работает - возможно, это связано с изменением API-интерфейса транзита, я не знаю, но пример скрипта не работает. Он запускает метод скрытия перед запуском анимации (пробовал в chrome)
Джонатан Лиути
@JonathanLiuti протестирован с использованием FireFox 25, IE11, Chrome 31. Работает отлично.
ROFLwTIME
Да @ROFLwTIME ты совершенно прав - кажется, мой хром просто сходил с ума. Перепробовал скрипку сегодня после чистого перезапуска хрома и он работает как положено. Виноват ! Извините насчет этого.
Джонатан Люти
14

Существует animationendсобытие, которое можно наблюдать, см. Документацию здесь , также для transitionанимации CSS вы можете использовать transitionendсобытие

Нет необходимости в дополнительных библиотеках, все они работают с vanilla JS

document.getElementById("myDIV").addEventListener("transitionend", myEndFunction);
function myEndFunction() {
	this.innerHTML = "transition event ended";
}
#myDIV {transition: top 2s; position: relative; top: 0;}
div {background: #ede;cursor: pointer;padding: 20px;}
<div id="myDIV" onclick="this.style.top = '55px';">Click me to start animation.</div>

Иегуда Шварц
источник
2
Это только пограничный ответ . Вы должны расширить свой ответ, чтобы включить сюда как можно больше информации, и использовать ссылку только для справки.
Прощай, StackExchange,
4
Голосуйте за это, так как это первое, которое не зависит от jQuery. Нет смысла вырубать целое дерево за ветку.
Аарон Мейсон
7

Для тех, кому это может пригодиться, вот зависимая от jQuery функция, с которой я успешно справился, применив CSS-анимацию через класс CSS, а затем получил обратный вызов. Возможно, он не работает идеально, поскольку он использовался в приложении Backbone.js, но, возможно, полезен.

var cssAnimate = function(cssClass, callback) {
    var self = this;

    // Checks if correct animation has ended
    var setAnimationListener = function() {
        self.one(
            "webkitAnimationEnd oanimationend msAnimationEnd animationend",
            function(e) {
                if(
                    e.originalEvent.animationName == cssClass &&
                    e.target === e.currentTarget
                ) {
                    callback();
                } else {
                    setAnimationListener();
                }
            }
        );
    }

    self.addClass(cssClass);
    setAnimationListener();
}

Я использовал это вроде как это

cssAnimate.call($("#something"), "fadeIn", function() {
    console.log("Animation is complete");
    // Remove animation class name?
});

Оригинальная идея от http://mikefowler.me/2013/11/18/page-transitions-in-backbone/

И это кажется удобным: http://api.jqueryui.com/addClass/


Обновить

После борьбы с приведенным выше кодом и другими опциями я бы предложил быть очень осторожным с любым прослушиванием концов CSS-анимации. При наличии нескольких анимаций это может очень быстро запутаться для прослушивания событий. Я настоятельно рекомендую использовать библиотеку анимации, такую ​​как GSAP, для каждой анимации, даже для небольших.

Дэвид Синклер
источник
Спасибо за то, что поделились, я использовал это и отредактировал добавление e.stopImmediatePropagation(); self.trigger(this.whichAnimationEvent()); //for purge existing event callback.apply(self);
BomAle
5

Принятый ответ в настоящее время запускается дважды для анимации в Chrome. Предположительно, это потому, что он признает, webkitAnimationEndа также animationEnd. Следующее, безусловно, будет срабатывать только один раз:

/* From Modernizr */
function whichTransitionEvent(){

    var el = document.createElement('fakeelement');
    var transitions = {
        'animation':'animationend',
        'OAnimation':'oAnimationEnd',
        'MSAnimation':'MSAnimationEnd',
        'WebkitAnimation':'webkitAnimationEnd'
    };

    for(var t in transitions){
        if( transitions.hasOwnProperty(t) && el.style[t] !== undefined ){
            return transitions[t];
        }
    }
}

$("#elementToListenTo")
    .on(whichTransitionEvent(),
        function(e){
            console.log('Transition complete!  This is the callback!');
            $(this).off(e);
        });
Чак Ле Батт
источник
3
Я бы предложил вместо этого вызывать функцию whichAnimationEvent (), поскольку она имеет дело с событиями анимации.
Якоб Лёкке Мэдсен