Callback of .animate() gets called twice jquery

2019-01-02 23:07发布

Since I added some scrollTop-animation, some parts of my callback get called twice:

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

It only seems to repeat the .show(), at least I don't have the impression that the load() or the .fadeIn() get called a second time too. The .show() gets repeated as soon as it has finished for the first time. Setting the scrollTop animation-speed to 0 didn't help by the way!

I assume it has something to do with the animation-queue, but I can't figure out how to find a workaround and especially why this is happening.

2条回答
孤傲高冷的网名
2楼-- · 2019-01-02 23:24

animate calls its callback once for each element in the set you call animate on:

If supplied, the start, step, progress, complete, done, fail, and always callbacks are called on a per-element basis...

Since you're animating two elements (the html element, and the body element), you're getting two callbacks. (For anyone wondering why the OP is animating two elements, it's because the animation works on body on some browsers but on html on other browsers.)

To get a single callback when the animation is complete, the animate docs point you at using the promise method to get a promise for the animation queue, then using then to queue the callback:

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

(Note: Kevin B pointed this out in his answer when the question was first asked. I didn't until four years later when I noticed it was missing, added it, and...then saw Kevin's answer. Please give his answer the love it deserves. I figured as this is the accepted answer, I should leave it in.)

Here's an example showing both the individual element callbacks, and the overall completion callback:

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>

查看更多
兄弟一词,经得起流年.
3楼-- · 2019-01-02 23:37

To get a single callback for the completion of multiple element animations, use deferred objects.

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

See the jQuery API for detailed description of the Promise and Deferred Objects.

查看更多
登录 后发表回答