web-dev-qa-db-fra.com

Le rappel de .animate () est appelé deux fois jquery

Depuis que j'ai ajouté une animation scrollTop-, certaines parties de mon rappel sont appelées deux fois:

$('html, body').animate({scrollTop: '0px'}, 300,function() {
    $('#content').load(window.location.href, postdata, function() {                 
        $('#step2').addClass('stepactive').hide().fadeIn(700, function() {
            $('#content').show('slide',800);                    
        });
    });
});

Il ne semble que répéter la .show(), du moins je n'ai pas l'impression que la load() ou la .fadeIn() soient appelées une deuxième fois aussi. La .show() est répétée dès qu'elle est terminée pour la première fois. La définition de la vitesse d'animation scrollTop sur 0 N'a d'ailleurs pas aidé!

Je suppose que cela a quelque chose à voir avec la file d'attente d'animation, mais je ne peux pas comprendre comment trouver une solution de contournement et surtout pourquoi cela se produit.

97
Anonymous

animate appelle son rappel une fois pour chaque élément de l'ensemble que vous appelez animate sur :

S'ils sont fournis, les start, step, progress, complete, done, fail et always les rappels sont appelés sur une base par élément ...

Puisque vous animez deux éléments (l'élément html et l'élément body), vous obtenez deux rappels. (Pour tous ceux qui se demandent pourquoi l'OP anime deux éléments, c'est parce que l'animation fonctionne sur body sur certains navigateurs mais sur html sur d'autres navigateurs.)

Pour obtenir un rappel unique une fois l'animation terminée, les documents animate vous indiquent comment utiliser promise méthode pour obtenir une promesse pour la file d'attente d'animation, puis en utilisant then pour mettre en file d'attente le rappel:

$("html, body").animate(/*...*/)
    .promise().then(function() {
        // Animation complete
    });

(Remarque: Kevin B l'a souligné dans sa réponse quand la question a été posée pour la première fois. Je n'ai attendu que quatre ans plus tard quand j'ai remarqué qu'elle manquait et j'ai ensuite vu la réponse de Kevin. S'il vous plaît, donnez à sa réponse l'amour qu'elle mérite. Je me suis dit que c'était la réponse acceptée, je devrais la laisser.)

Voici un exemple montrant à la fois les rappels d'éléments individuels et le rappel d'achèvement global:

jQuery(function($) {

  $("#one, #two").animate({
    marginLeft: "30em"
  }, function() {
    // Called per element
    display("Done animating " + this.id);
  }).promise().then(function() {
    // Called when the animation in total is complete
    display("Done with animation");
  });

  function display(msg) {
    $("<p>").html(msg).appendTo(document.body);
  }
});
<div id="one">I'm one</div>
<div id="two">I'm two</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
152
T.J. Crowder

Pour obtenir un seul rappel pour l'achèvement de plusieurs animations d'éléments, utilisez des objets différés.

$(".myClass").animate({
  marginLeft: "30em"
}).promise().done(function(){
  alert("Done animating");
});

Voir l'API jQuery pour une description détaillée des Promise et Objets différés .

167
Kevin B