.animate()のコールバックが2回jqueryで呼び出される


103

scrollTop-animation を追加したので、コールバックの一部が2回呼び出されます。

$('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()すぐにそれが最初に終了したように繰り返されます。0ちなみに、scrollTopのアニメーション速度をに設定しても効果はありませんでした。

それはアニメーションキューと関係があると思いますが、回避策を見つける方法、特にこれが発生している理由を理解できません。

回答:


162

animateコールバックするセットの要素ごとに 1回コールバックを呼び出しますanimate

指定した場合、startstepprogresscompletedonefail、およびalwaysコールバックは上と呼ばれている要素ごとの基礎 ...

2つの要素(html要素とbody要素)をアニメーション化しているので、2つのコールバックを取得しています。OPがなぜ2つの要素をアニメーション化しているの疑問に思う方は、アニメーションbodyが一部のブラウザーでは機能するがhtml他のブラウザーでは機能するためです。)

アニメーションが完了したときに単一のコールバックを取得するには、animateドキュメントで、promiseメソッドを使用してアニメーションキューのpromiseを取得し、次にを使用thenしてコールバックをキューに入れるように指示します。

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

(注:質問が最初に尋ねられたとき、ケビンB は彼の回答でこれを指摘しました。4年後、それが欠落していることに気づき、それを追加してから、ケビンの回答を見つけました。彼の回答を教えてください。愛するに値する。これは受け入れられる答えだと思ったので、そのままにしておく必要がある。)

以下は、個々の要素のコールバックと全体的な完了コールバックの両方を示す例です。

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>


2
ええそれが理由でした、そして実際に私は今まで書いた理由を思い出すことができませんhtml, body。私の脳を元に戻す時が来ました。ありがとう
匿名

21
おそらく、htmlだけをアニメーション化してもWebkitでは機能せず、bodyだけではOperaで機能しないためです。両方を使用すると、常に機能しますが、Firefoxではコールバックが2回トリガーされます。(ブラウザを間違えた可能性があります...)
Jon Gjengset

2
htmlIEには必須であり、他のほとんどのブラウザではコールバックが2回起動します。同じ問題の解決策を模索しています。
Simon Robb 2013

9
私はフラグを作成して対処しました。 var ranOne = false; $('body,html').animate({ scrollTop: scrollTo }, scrollTime, 'swing', function () { if (ranOne) { ...action... ranOne = false; } else { ranOne = true; } }); それはハックに感じますが、「body、html」を使用する必要があるのはそもそもハックの一種です。(改行がないため申し訳ありませんが、コメントには表示されないと思います)
2013

1
信じられない!$( "html、body")を使用してスクロールアニメーションを適切に機能させ、2回起動しないようにするために何時間も費やしましたが、この答えが私を救いました。ありがとう!
Vasily Hall

172

複数の要素のアニメーションを完了するための単一のコールバックを取得するには、遅延オブジェクトを使用します。

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

Promise オブジェクトDeferredオブジェクトの詳細については、jQuery APIを参照してください。


これは、アニメーションの終了時に何をしたいのかという問題を解決しましたが、約2回の呼び出しを発行して+1を取得しましたが、アニメーションプロセスが2回呼び出されたかどうかわかりません!
QMaster、2014年

1
アニメーションプロセスは2回呼び出されません。コールバックは、選択された要素ごとに1回呼び出されます。したがって、8つのリストアイテムを選択して左にアニメーション化すると、コールバックは8回実行されます。私の解決策では、8つすべてが完了したときに1つのコールバックを提供します。
Kevin B

@KevinB、良い解決策、そしてそれは私自身のコールバック問題の解決にも役立ちました。ありがとう。
lislis 2015年

これは興味深い答えだと思いましたが、残念ながら意図しない結果が生じています。promiseは、jQueryセットの要素が現在のアニメーションを終了するまで、コールバックの実行を遅らせるだけではありません(すばらしいでしょう)。セットのすべての保留中のアニメーションが行われた後でのみ解決されます。したがって、最初のアニメーションの実行中に2番目のアニメーションがセットアップされた場合、最初のアニメーションを対象としたコールバックは、2番目のアニメーションが終了するまで実行されません。このビンを参照してください。
hashchangeは

1
正解です。選択した要素の現在のアニメーションがすべて完了するまで待機します。このチェーンで開始されたものを待つだけでは十分ではありません(そうであるべきではありません)
Kevin B
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.