Rappel lorsque la transition CSS3 se termine

202

Je voudrais effacer un élément (en faisant passer son opacité à 0), puis une fois terminé, supprimez l'élément du DOM.

Dans jQuery, cela est simple car vous pouvez spécifier que la «suppression» doit se produire après la fin d'une animation. Mais si je souhaite animer en utilisant des transitions CSS3, est-il possible de savoir quand la transition / animation est terminée?

CJ
la source
3
devrait être similaire à ceci: stackoverflow.com/questions/6186454/…
Nicolas Modrzyk

Réponses:

334

Pour les transitions, vous pouvez utiliser les éléments suivants pour détecter la fin d'une transition via jQuery:

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

Mozilla a une excellente référence:

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

Pour les animations, c'est très similaire:

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

Notez que vous pouvez passer simultanément toutes les chaînes d'événements préfixées du navigateur dans la méthode bind () pour prendre en charge le déclenchement de l'événement sur tous les navigateurs qui le prennent en charge.

Mettre à jour:

Selon le commentaire laissé par Duck: vous utilisez la .one()méthode de jQuery pour vous assurer que le gestionnaire ne se déclenche qu'une seule fois. Par exemple:

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

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

Mise à jour 2:

La bind()méthode jQuery est obsolète et la on()méthode est préférée à partir de jQuery 1.7.bind()

Vous pouvez également utiliser la off()méthode sur la fonction de rappel pour vous assurer qu'elle ne sera déclenchée qu'une seule fois. Voici un exemple qui équivaut à utiliser la one()méthode:

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

Références:

Jim Jeffers
la source
13
Il convient de noter que le rappel sera déclenché pour chaque élément enfant qui transite également. Il est très important de garder cela à l'esprit au cas où vous vous demanderiez pourquoi votre rappel est renvoyé plus de fois que prévu. Je ne suis au courant d'aucune solution de contournement pour l'instant.
Lev
22
@Lev, vous pouvez facilement atténuer cela en comparant la cible actuelle de l'événement à sa cible. Donc quelque chose comme: function (event) {if (event.target === event.currentTarget) {/ * Do stuff * /}}
Jim Jeffers
5
Oui, je l'ai compris peu de temps après avoir écrit le commentaire. > _ <Merci de l'avoir posté cependant; Je suis sûr que cela aidera les autres! :)
Lev
9
Nous utilisons .on()plutôt que .bind()pour jQuery v1.7 + api.jquery.com/bind
olo
4
Tous les navigateurs modernes prennent désormais en charge l'événement non préfixé. caniuse.com/#feat=css-transitions Notez également que si vous avez "transitionend webkitTransitionEnd", il sera déclenché deux fois dans Chrome.
Michael S.
17

Une autre option consisterait à utiliser jQuery Transit Framework pour gérer vos transitions CSS3. Les transitions / effets fonctionnent bien sur les appareils mobiles et vous n'avez pas à ajouter une seule ligne de transitions CSS3 désordonnées dans votre fichier CSS pour effectuer les effets d'animation.

Voici un exemple qui passera l'opacité d'un élément à 0 lorsque vous cliquerez dessus et sera supprimé une fois la transition terminée:

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

JS Fiddle Demo

ROFLwTIME
la source
Le rappel ne fonctionne pas - peut-être est-ce dû à un changement dans l'API du transit, je ne sais pas, mais l'exemple du violon ne fonctionne pas. Il déclenche la méthode hide avant l'exécution de l'animation (essayé en chrome)
Jonathan Liuti
@JonathanLiuti testé avec FireFox 25, IE11, Chrome 31. Fonctionne très bien.
ROFLwTIME
Oui @ROFLwTIME vous avez tout à fait raison - il semble que mon chrome devienne fou. Réessayé le violon aujourd'hui après un redémarrage propre de Chrome et il fonctionne comme prévu. Ma faute ! Désolé pour celui-ci.
Jonathan Liuti
14

Il y a un animationendévénement qui peut être observé voir la documentation ici , aussi pour les transitionanimations css vous pouvez utiliser letransitionend événement

Il n'y a pas besoin de bibliothèques supplémentaires qui fonctionnent toutes avec 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>

Yehuda Schwartz
la source
2
Il s'agit d'une réponse de lien limite uniquement . Vous devez développer votre réponse pour inclure autant d'informations ici et utiliser le lien uniquement à titre de référence.
Au revoir StackExchange
4
Voter celui-ci car c'est le premier qui ne repose pas sur jQuery. Pas de sens de couper un arbre entier pour une branche.
Aaron Mason
7

Pour tous ceux qui pourraient être utiles, voici une fonction dépendante de jQuery avec laquelle j'ai réussi à appliquer une animation CSS via une classe CSS, puis à obtenir un rappel par la suite. Cela peut ne pas fonctionner parfaitement depuis que je l'ai utilisé dans une application Backbone.js, mais peut-être 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();
}

Je l'ai utilisé un peu comme ça

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

Idée originale de http://mikefowler.me/2013/11/18/page-transitions-in-backbone/

Et cela semble pratique: http://api.jqueryui.com/addClass/


Mettre à jour

Après avoir lutté avec le code ci-dessus et d'autres options, je suggère d'être très prudent avec toute écoute des fins d'animation CSS. Avec plusieurs animations en cours, cela peut devenir très rapidement désordonné pour l'écoute des événements. Je suggère fortement une bibliothèque d'animation comme GSAP pour chaque animation, même les plus petites.

David Sinclair
la source
Merci de le partager, je l'ai utilisé et édité en ajoutant e.stopImmediatePropagation(); self.trigger(this.whichAnimationEvent()); //for purge existing event callback.apply(self);
BomAle
5

La réponse acceptée se déclenche actuellement deux fois pour les animations dans Chrome. Vraisemblablement, c'est parce qu'il reconnaît webkitAnimationEndaussi bien que animationEnd. Les éléments suivants ne se déclencheront certainement qu'une seule fois:

/* 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);
        });
Chuck Le Butt
la source
3
Je suggère d'appeler la fonction whichAnimationEvent () à la place, car elle traite des événements d'animation.
Jakob Løkke Madsen