Зворотний виклик після завершення переходу CSS3


202

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

У jQuery це прямо вперед, оскільки ви можете вказати "Видалити", щоб відбутися після завершення анімації. Але якщо я хочу анімувати за допомогою CSS3 переходів, чи все-таки потрібно знати, коли перехід / анімація завершився?


3
повинен бути схожий на це: stackoverflow.com/questions/6186454 / ...
Ніколя Modrzyk

Відповіді:


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 () одночасно для підтримки запуску події у всіх браузерах, які його підтримують.

Оновлення:

Відповідно до коментаря, який залишив Дак: ви використовуєте .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 ви можете легко пом'якшити це, порівнявши поточний ціль події з цільовою ціллю. Тож щось на кшталт: 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


Зворотний виклик не працює - можливо, це пов'язано зі зміною api транзиту, якого я не знаю, але приклад загадки не працює. Він запускає метод приховування перед
запуском

@JonathanLiuti тестовано за допомогою FireFox 25, IE11, Chrome 31. Добре працює.
ROFLwTIME

Так @ROFLwTIME ви абсолютно праві - здається, мій хром просто з глузду з’їхав. Сьогодні переглянув скрипку після чистого перезавантаження хрому, і він працює як очікувалося. Моє ліжко ! Вибачте за це.
Джонатан Люті

14

Є animationendподія, яку можна спостерігати, дивіться тут документацію , також для transitionанімації css, яку ви могли використовуватиtransitionend подія

Немає необхідності в додаткових бібліотеках, всі вони працюють з ванільним 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
Це відповідь лише для прикордонних посилань . Ви повинні розширити свою відповідь, щоб включити сюди якомога більше інформації та використовувати посилання лише для довідки.
Goodbye 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
Я б запропонував назвати функцію thatAnimationEvent () натомість, оскільки вона стосується подій анімації.
Jakob Løkke Madsen
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.