Richiamata al termine della transizione CSS3


202

Vorrei sfumare un elemento (spostando la sua opacità su 0) e, al termine, rimuovere l'elemento dal DOM.

In jQuery questo è semplice poiché è possibile specificare che "Rimuovi" si verifichi al termine di un'animazione. Ma se desidero animare usando le transizioni CSS3, c'è comunque modo di sapere quando la transizione / animazione è stata completata?


3
dovrebbe essere simile a questo: stackoverflow.com/questions/6186454/...
Nicolas Modrzyk

Risposte:


334

Per le transizioni è possibile utilizzare quanto segue per rilevare la fine di una transizione tramite jQuery:

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

Mozilla ha un riferimento eccellente:

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

Per le animazioni è molto simile:

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

Si noti che è possibile passare contemporaneamente tutte le stringhe di eventi con prefisso del browser nel metodo bind () per supportare l'attivazione dell'evento su tutti i browser che lo supportano.

Aggiornare:

Secondo il commento lasciato da Duck: usi il .one()metodo di jQuery per assicurarti che il gestore funzioni solo una volta. Per esempio:

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

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

Aggiornamento 2:

Il bind()metodo jQuery è stato deprecato e il on()metodo è preferito al momento jQuery 1.7.bind()

È inoltre possibile utilizzare il off()metodo sulla funzione di callback per assicurarsi che venga attivato una sola volta. Ecco un esempio equivalente all'utilizzo del one()metodo:

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

Riferimenti:


13
Vale la pena notare che il callback verrà attivato anche per ogni elemento figlio che transita. Questo è molto importante da tenere a mente nel caso ti stia chiedendo perché il tuo callback viene attivato più volte di quanto ti aspettassi. Non sono a conoscenza di alcuna soluzione al momento.
Lev

22
@Lev potresti facilmente mitigarlo confrontando il target attuale dell'evento con il suo target. Quindi qualcosa come: function (event) {if (event.target === event.currentTarget) {/ * Do stuff * /}}
Jim Jeffers,

5
Sì, l'ho capito poco dopo aver scritto il commento. > _ <Grazie per averlo pubblicato comunque; Sono sicuro che aiuterà gli altri! :)
Lev

9
Usiamo .on()piuttosto che .bind()per jQuery v1.7 + api.jquery.com/bind
olo

4
Tutti i browser moderni ora supportano l'evento non risolto. caniuse.com/#feat=css-transitions Nota anche che se hai "transizione webkitTransitionEnd" verrà attivato due volte in Chrome.
Michael S.

17

Un'altra opzione sarebbe quella di utilizzare jQuery Transit Framework per gestire le transizioni CSS3. Le transizioni / effetti funzionano bene sui dispositivi mobili e non è necessario aggiungere una sola riga di transizioni CSS3 disordinate nel file CSS per eseguire gli effetti di animazione.

Ecco un esempio che passerà a 0 l'opacità di un elemento quando fai clic su di esso e verrà rimosso al termine della transizione:

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

JS Fiddle Demo


Il callback non funziona - forse è dovuto a un cambiamento nell'api del transito che non conosco, ma l'esempio del violino non funziona. Attiva il metodo hide prima che l'animazione venga eseguita (provato in Chrome)
Jonathan Liuti,

@JonathanLiuti testato con FireFox 25, IE11, Chrome 31. Funziona bene.
ROFLwTIME

Sì @ROFLwTIME hai perfettamente ragione - sembra che il mio Chrome sia impazzito. Riprovare il violino oggi dopo un riavvio pulito di Chrome e funziona come previsto. Colpa mia ! Mi dispiace per questo.
Jonathan Liuti il

14

C'è un animationendevento che può essere osservato vedi la documentazione qui , anche per le transitionanimazioni CSS puoi usare l' transitionendevento

Non sono necessarie ulteriori librerie che funzionano tutte con 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
Questa è una risposta solo al collegamento borderline . È necessario espandere la risposta per includere quante più informazioni qui e utilizzare il collegamento solo come riferimento.
Arrivederci StackExchange il

4
Votando questo perché è il primo a non fare affidamento su jQuery. Non ha senso tagliare un intero albero per un ramo.
Aaron Mason,

7

Per chiunque possa essere utile, ecco una funzione dipendente da jQuery con cui ho avuto successo con l'applicazione di un'animazione CSS tramite una classe CSS, per poi ottenere una richiamata da allora in poi. Potrebbe non funzionare perfettamente poiché l'ho usato in un'app Backbone.js, ma forse utile.

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();
}

L'ho usato in questo modo

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

Idea originale da http://mikefowler.me/2013/11/18/page-transitions-in-backbone/

E questo sembra utile: http://api.jqueryui.com/addClass/


Aggiornare

Dopo aver lottato con il codice sopra e altre opzioni, suggerirei di essere molto cauto con qualsiasi ascolto per fini dell'animazione CSS. Con animazioni multiple in corso, questo può diventare molto veloce per l'ascolto di eventi. Consiglio vivamente una libreria di animazioni come GSAP per ogni animazione, anche per quelle piccole.


Grazie per condividerlo, l'ho usato e modificato aggiungendo e.stopImmediatePropagation(); self.trigger(this.whichAnimationEvent()); //for purge existing event callback.apply(self);
BomAle

5

La risposta accettata attualmente viene emessa due volte per le animazioni in Chrome. Presumibilmente questo è perché riconosce webkitAnimationEndanche animationEnd. Il seguente si accenderà sicuramente solo una volta:

/* 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
Suggerirei invece di chiamare la funzione whichAnimationEvent (), poiché si occupa di eventi di animazione.
Jakob Løkke Madsen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.