Зворотний виклик .animate () викликається двічі jquery


103

Оскільки я додав деяку 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не допомогло!

Я припускаю, що це має щось спільне з чергою анімації, але я не можу зрозуміти, як знайти обхід, і особливо, чому це відбувається.

Відповіді:


162

animateвикликає зворотний виклик один раз для кожного елемента в наборі, на який ви дзвоните animate:

При поставці, то start, step, progress, complete, done, fail, і alwaysзворотні виклики називаються на основі кожного елемента ...

Оскільки ви анімуєте два елементи ( htmlелемент і bodyелемент), ви отримуєте два зворотних виклику. (Для всіх, хто цікавиться, чому ОП анімує два елементи, це тому, що анімація працює bodyв деяких браузерах, а htmlв інших браузерах.)

Щоб отримати єдиний зворотний виклик, коли анімація завершена, animateдокументи вказують на використання promiseметоду, щоб отримати обіцянку для черги анімації, а потім використовувати thenдля черги зворотного дзвінка:

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

(Примітка: Кевін Б. вказав на це у своїй відповіді, коли запитання було вперше поставлено. Я був лише через чотири роки, коли помітив, що він відсутній, додав його, і ... потім побачив відповідь Кевіна. Будь ласка, дайте його відповідь Люблю це заслуговує. Я зрозумів, що це прийнята відповідь, я повинен залишити її.)

Ось приклад, що показує як виклики окремих елементів, так і загальний зворотний виклик завершення:

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, і просто тіло не працюватиме в Opera. Використання обох забезпечить це завжди працює, але двічі запустить зворотний виклик у Firefox. (Можливо, я помилився з браузерами ...)
Джон Gjengset

2
htmlпотрібен для IE, і зворотний виклик буде активовано двічі для більшості інших браузерів. Я намагаюсь вирішити ту саму проблему.
Саймон Робб

9
Я розібрався з цим, створивши прапор: var ranOne = false; $('body,html').animate({ scrollTop: scrollTo }, scrollTime, 'swing', function () { if (ranOne) { ...action... ranOne = false; } else { ranOne = true; } }); він відчуває себе хакі, але використання "body, html" - це в першу чергу хакі. (вибачте за відсутність розривів рядків, гадаю, коментарі не показують їх)
1313

1
Неймовірно! Я витратив години, намагаючись змусити свою анімаційну прокрутку працювати належним чином з $ ("html, body"), щоб вона не запускалася двічі, і ця відповідь мене врятувала! Дякую!
Василь Холл

172

Щоб отримати єдиний зворотний виклик для завершення анімації з декількома елементами, використовуйте відкладені об'єкти.

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

Дивіться API jQuery для детального опису Обіцянь та Відкладених Об'єктів .


Це вирішена проблема щодо того, що ми хочемо зробити на завершеній анімації, але питання про два рази дзвінки та отримав +1 за це, але я не знаю, анімований процес викликається двічі чи ні ?!
QMaster

1
Процес анімації не викликається двічі, зворотний виклик викликається один раз для кожного вибраного елемента. Отже, якщо ви виберете 8 елементів списку та анімуєте їх зліва, зворотний виклик буде виконано 8 разів. Моє рішення дає вам єдиний зворотний дзвінок, коли всі 8 завершені.
Кевін Б

@KevinB, гарне рішення, і це також допомогло вирішити мої власні проблеми із зворотним дзвінкам. Дякую.
lislis

Я вважав, що це інтригуюча відповідь, але, на жаль, це має ненавмисні наслідки. Обіцянка не просто затримує виконання зворотного виклику, поки елементи набору jQuery не закінчать поточну анімацію (що було б чудово). Це вирішується лише після того, як будуть виконані всі очікувані анімації набору. Отже, якщо друга анімація налаштована, поки перша все ще працює, зворотний виклик, призначений для першої анімації, не запускається, поки не закінчиться друга анімація. Дивіться цю кошик .
hashchange

1
Це правильно, він чекає завершення всіх поточних анімацій для вибраних елементів. Це не досить розумно, щоб лише чекати тих, що розпочалися в цьому ланцюжку (і не повинно бути)
Кевін Б,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.