2009-08-02 6 views
31

Я думал, что это будет просто, но я все еще не могу заставить его работать. Нажимая одну кнопку, я хочу, чтобы произошло несколько анимаций: один за другим - но теперь все анимации происходят сразу. Вот мой код - может кто-то пожалуйста, скажите мне, где я буду неправильно ?:Как я могу анимировать несколько элементов последовательно с помощью 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"); 
}); 
+0

6.9kb прокомментирован, без ограничений и без gzip. Prob <1kb на самом деле – redsquare

+1

Я искал, чтобы сделать очень похожее на этот вопрос, поэтому я создал небольшой JQuery-плагин (https://github.com/fillswitch/Jquery-Sequential-Animations). Надеюсь, это поможет некоторым другим! –

ответ

23

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

$(".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");   
      }); 
     }); 
    }); 
}); 
+0

см. Выше! , – redsquare

+0

Это сработало. Приветствует jammus. – lnvrt

+4

У меня была аналогичная проблема на моем веб-сайте, и с тех пор я думал об использовании обратных вызовов, но, похоже, это немного нелестно. было бы хорошо, если бы вы могли как-то это сделать с помощью jquery chaining. на данный момент я делаю это, используя функцию задержки: анимировать первое. задерживайте вторую вещь тем же количеством времени, когда я анимирую первое, а затем оживляю его и т. д. – MrVimes

-8

Используйте опцию 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" }); 
}); 
+0

Спасибо Garrett, но это не сработало ... – lnvrt

+0

queue is true по умолчанию – redsquare

+0

так, что делать? – lnvrt

28

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

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

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

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

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

Да, обратные вызовы были тем, что я собирался предложить. –

+0

Спасибо redsquare. Но так как не будет много анимаций, я не думаю, что есть необходимость в плагине (дополнительный 6.26kb). Однако я буду помнить это о будущем. – lnvrt

+0

спасибо за информацию @redsquare. :) –

1

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

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

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

1

Это уже ответили хорошо (я думаю, что ответ 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)

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

+0

Это не похоже на очень динамичную метод, который вы должны вручную обновить эти значения. – neufuture

+0

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

+0

Простое быстрое решение +1 – suspectus

2

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

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

Here is a fiddle

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

Я знаю, что это старый вопрос, но он должен быть обновлен с ответом на новые версии 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");   
}); 
+0

Хорошее обновление! Очень аккуратный и работает по назначению. – Bora

+2

Это очень хороший узор. Еще одно предложение - IE 8 (по крайней мере) имеет дело с объектом «аргументы» по-разному. Во-первых, он должен быть создан как истинный массив, тогда для метода .splice нужны оба параметра. Используйте \t var args = Array.prototype.slice.звоните (аргументы); \t var rest = [] .splice.call (args, 1, args.length-1); – jschrab

+1

Спасибо, это очень помогло мне. –

6

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

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

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

Работа с Plain объектов

В настоящее время единственные операции, поддерживаемые на простых объектов JavaScript, завернутые в JQuery являются: .data() ,. проп() ,. Bind(), .unbind() , .trigger() и .triggerHandler().

+2

Это изящное решение, так как оно позволяет избежать глубоко вложенных обратных вызовов. Я собрал немного [jsFiddle] (http://jsfiddle.net/philippm/SFLAB/), который вставляет это в действие. Что касается поддержки обернутых простых объектов: [этот официальный учебник jQuery] (http://learn.jquery.com/effects/uses-of-queue-and-dequeue/) использует тот же подход. – Philipp

2

анимировать несколько Теги Последовательная

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

// 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() просто вызывает вызов анимации вашего тега, но он ставит его в очередь на теге тела.

  2. Когда jQuery удаляет анимацию вашего тега в очереди на тело, анимация вашего тега начинается в очереди для вашего тега, но, как работает анимационная среда jQuery, любой пользовательский обратный вызов анимации вызывает очередь анимации тега (тело в этот случай) для остановки, пока пользовательская анимация не вызовет функцию переданного 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/

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

Смежные вопросы