Как можно последовательно анимировать несколько элементов с помощью jQuery?



Я думал, что это будет просто, но я все еще не могу заставить его работать. Нажав одну кнопку, Я хочу, чтобы произошло несколько анимаций - одна за другой - но теперь все анимации происходят одновременно. Вот мой код - может кто-нибудь, пожалуйста, сказать мне, где я ошибаюсь?:



$(".button").click(function(){
$("#header").animate({top: "-50"}, "slow")
$("#something").animate({height: "hide"}, "slow")
$("ul#menu").animate({top: "20", left: "0"}, "slow")
$(".trigger").animate({height: "show", top: "110", left: "0"}, "slow");
});
638   9  

9 ответов:

Вы можете сделать кучу обратных вызовов.

$(".button").click(function(){
    $("#header").animate({top: "-50"}, "slow", function() {
        $("#something").animate({height: "hide"}, "slow", function() {
            $("ul#menu").animate({top: "20", left: "0"}, "slow", function() {
                $(".trigger").animate({height: "show", top: "110", left: "0"}, "slow");        
            });
        });
    });
});

Очередь работает только в том случае, если вы анимируете один и тот же элемент. Бог знает, почему за это проголосовали, но это не сработает.

Вам нужно будет использовать обратный вызов анимации. Вы можете передать функцию в качестве последнего парама функции animate, и она будет вызвана после завершения анимации. Однако если у вас есть несколько вложенных анимаций с обратными вызовами, сценарий будет довольно нечитабельным.

Я предлагаю следующий плагин, который перезаписывает родной jQuery animate функция и позволяет указать имя очереди. Все анимации, которые вы добавляете с тем же именем очереди, будут выполняться последовательно, как показано здесь .

Пример сценария

  $("#1").animate({marginTop: "100px"}, {duration: 100, queue: "global"});
  $("#2").animate({marginTop: "100px"}, {duration: 100, queue: "global"});
  $("#3").animate({marginTop: "100px"}, {duration: 100, queue: "global"});

Я знаю, что это старый вопрос, но он должен быть обновлен с ответом для более новых версий jQuery (1.5 и выше):

Используя функцию $.when, Вы можете написать этот помощник:

function queue(start) {
    var rest = [].splice.call(arguments, 1),
        promise = $.Deferred();

    if (start) {
        $.when(start()).then(function () {
            queue.apply(window, rest);
        });
    } else {
        promise.resolve();
    }
    return promise;
}

Тогда вы можете назвать это так:

queue(function () {
    return $("#header").animate({top: "-50"}, "slow");
}, function () {
    return $("#something").animate({height: "hide"}, "slow");
}, function () {
    return $("ul#menu").animate({top: "20", left: "0"}, "slow");
}, function () {
    return $(".trigger").animate({height: "show", top: "110", left: "0"}, "slow");        
});

Небольшое улучшение в ответе @schmunk заключается в использовании простой очереди объекта jQuery, чтобы избежать конфликта с другими несвязанными анимациями:

$({})
    .queue(function (next) {
        elm1.fadeOut('fast', next);
    })
    .queue(function (next) {
        elm2.fadeIn('fast', next);
    })
    // ...

Следует иметь в виду, что, хотя я никогда не сталкивался с проблемами при этом, согласно docs Использование методов очереди на простой оболочке объекта официально не поддерживается.

Работа С Простыми Объектами

В настоящее время поддерживаются только операции на обычном JavaScript объекты, завернутые в jQuery АР: .данные(),.прислонить(),.связывать(), .развязывать(), .триггер и .triggerHandler().

Продолжая ответ джаммуса, это, возможно, немного более практично для длинных последовательностей анимаций. Отправьте список, анимируйте каждого по очереди, рекурсивно вызывая animate снова с уменьшенным списком. Выполните обратный вызов, когда все закончено.

Список здесь состоит из выбранных элементов, но это может быть список более сложных объектов, содержащих различные параметры анимации для каждой анимации.

Вот скрипка

$(document).ready(function () {
    animate([$('#one'), $('#two'), $('#three')], finished);
});

function finished() {
    console.log('Finished');
}

function animate(list, callback) {
    if (list.length === 0) {
        callback();
        return;
    }
    $el = list.shift();
    $el.animate({left: '+=200'}, 1000, function () {
        animate(list, callback);
    });
}

Анимация Нескольких Тегов Последовательно

Вы можете использовать встроенную анимационную очередь jQuery, если просто выберете тег, подобный body, чтобы сделать глобальную очередь:

// Convenience object to ease global animation queueing
$.globalQueue = {
    queue: function(anim) {
        $('body')
        .queue(function(dequeue) {
            anim()
            .queue(function(innerDequeue) {
                dequeue();
                innerDequeue();
            });
        });

        return this;
    }
};

// Animation that coordinates multiple tags
$(".button").click(function() {
    $.globalQueue
    .queue(function() {
        return $("#header").animate({top: "-50"}, "slow");
    }).queue(function() {
      return $("#something").animate({height: "hide"}, "slow");
    }).queue(function() {
        return $("ul#menu").animate({top: "20", left: "0"}, "slow");
    }).queue(function() {
        return $(".trigger").animate({height: "show", top: "110", left: "0"}, "slow");
    });
});

Http://jsfiddle.net/b9chris/wjpL31o0/

Итак, вот почему это работает, и что это делает:

  1. Вызов $.globalQueue.queue() - это просто очередь вызова анимации вашего тега,но он ставит ее в очередь на теге body.

  2. Когда jQuery попадает в ваш тег анимация в теле очередь, анимация вашего тега запускается в очереди для вашего тега - но так, как работает jQuery animation framework, любой обратный вызов пользовательской анимации вызывает остановку очереди анимации тега (в данном случае тела), пока пользовательская анимация не вызовет функцию passed-in dequeue(). Таким образом, несмотря на то, что очереди для вашего анимированного тега и тела разделены, очередь тега тела теперь ожидает вызова его dequeue(). http://api.jquery.com/queue/#queue-queueName-callback

  3. Мы просто делаем последний элемент очереди в очереди тега вызовом для продолжения глобальной очереди, вызывая его функцию dequeue() - это то, что связывает очереди вместе.

  4. Для удобства метод globalQueue.queue возвращает ссылку this для упрощения цепочки.

SetInterval

Для полноты картины здесь легко приземлиться, просто ища альтернативу setInterval - этому вы не столько хотите сделать отдельные анимации координированными, сколько просто запустить их с течением времени без странного всплеска вперед в вашей анимации, вызванного тем, как новые браузеры отложат очереди анимации и таймеры, чтобы сэкономить процессор.

Вы можете заменить вызов на setInterval следующим образом:

setInterval(doAthing, 8000);

С этим:

/**
 * Alternative to window.setInterval(), that plays nicely with modern animation and CPU suspends
 */
$.setInterval = function (fn, interval) {
    var body = $('body');
    var queueInterval = function () {
        body
        .delay(interval)
        .queue(function(dequeue) {
            fn();
            queueInterval();
            dequeue();  // Required for the jQuery animation queue to work (tells it to continue animating)
        });
    };
    queueInterval();
};

$.setInterval(doAthing, 8000);

Http://jsfiddle.net/b9chris/h156wgg6/

И избегайте этих неловких взрывов анимации, когда фоновая вкладка имеет свою анимацию повторно включается браузером.

Вы также можете поместить свои эффекты в ту же очередь, то есть очередь элемента BODY.

$('.images IMG').ready(
   function(){
        $('BODY').queue(
            function(){
                $('.images').fadeTo('normal',1,function(){$('BODY').dequeue()});
            }
        );
    }
);

Убедитесь, что вы вызываете dequeue () в последнем эффекте обратного вызова.

На этот вопрос уже был дан хороший ответ (я думаю, что ответ jammus является лучшим), но я подумал, что предложу другой вариант, основанный на том, как я делаю это на своем веб-сайте, используя функцию delay()...

  $(".button").click(function(){
     $("#header").animate({top: "-50"}, 1000)
     $("#something").delay(1000).animate({height: "hide"}, 1000)
     $("ul#menu").delay(2000).animate({top: "20", left: "0"}, 1000)
     $(".trigger").delay(3000).animate({height: "show", top: "110", left: "0"}, "slow");
});

(Замените 1000 на нужную скорость анимации. идея заключается в том, что ваша функция задержки задерживает на эту величину и накапливает задержку в анимации каждого элемента, поэтому, если бы ваши анимации были каждые 500 миллисекунд, ваши значения задержки были бы 500, 1000, 1500)

Edit: FYI jquery 'slow' скорость также составляет 600 миллисекунд. поэтому, если вы хотите использовать 'slow' все еще в ваших анимациях, просто используйте эти значения в каждом последующем вызове функции задержки-600, 1200, 1800

Используйте опцию queue:

$(".button").click(function(){
  $("#header").animate({top: "-50"}, { queue: true, duration: "slow" })
  $("#something").animate({height: "hide"}, { queue: true, duration: "slow" })
  $("ul#menu").animate({top: "20", left: "0"}, { queue: true, duration: "slow" })
  $(".trigger").animate({height: "show", top: "110", left: "0"}, { queue: true, duration: "slow" });
});

Comments

    Ничего не найдено.