对. animate()的回调调用两次 jquery

由于我添加了一些 scrollTop动画,我的回调函数的一些部分被调用了两次:

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

它似乎只是重复的 .show(),至少我没有印象的 load().fadeIn()得到第二次调用了。.show()第一次完成后就会重复执行。设置 scrollTop 动画-速度到 0没有帮助的方式!

我假设它与动画队列有关,但是我不知道如何找到一个变通方法,特别是 为什么,这正在发生。

29431 次浏览

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 ABC1 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>

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

When you call .animate on a collection, each element in the collection is animated individually. When each one is done, the callback is called. This means if you animate eight elements, you'll get eight callbacks. The .promise().done(...) solution instead gives you a single callback when all animations on those eight elements are complete. This does have a side-effect in that if there are any other animations occurring on any of those eight elements the callback won't occur until those animations are done as well.

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