¿Cómo puedo animar múltiples elementos secuencialmente usando jQuery?

Pensé que sería simple, pero aún no puedo hacer que funcione. Al hacer clic en un botón, quiero que ocurran varias animaciones, una tras otra , pero ahora todas las animaciones están sucediendo a la vez. Aquí está mi código: ¿alguien puede decirme dónde me estoy equivocando ?:

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

Podrías hacer un montón de devoluciones de llamadas.

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

La cola solo funciona si estás animando el mismo elemento. Dios sabe por qué lo de arriba se votó, pero no funcionará.

Tendrá que usar la callback de animación. Puede pasar una función como el último parámetro de la función animada y se llamará después de que la animación se haya completado. Sin embargo, si tiene múltiples animaciones anidadas con devoluciones de llamadas, la secuencia de comandos será bastante ilegible.

Sugiero el siguiente complemento que vuelve a escribir la función animada jQuery nativa y le permite especificar un nombre de cola. Todas las animaciones que agregue con el mismo nombre de cola se ejecutarán secuencialmente como se demuestra aquí .

Script de ejemplo

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

Sé que esta es una pregunta antigua, pero debería actualizarse con una respuesta para las versiones jQuery más recientes (1.5 y posteriores):

Usando la función $.when puedes escribir este ayudante:

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

Entonces puedes llamarlo así:

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

Una ligera mejora en la respuesta de @ schmunk es usar una cola de objetos jQuery de objetos simples para evitar conflictos con otras animaciones no relacionadas:

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

Una cosa a tener en cuenta es que, aunque nunca me he encontrado con problemas al hacer esto, de acuerdo con los documentos que utilizan los métodos de cola en un contenedor de objetos simples no es oficialmente compatible.

Trabajando con objetos simples

En la actualidad, las únicas operaciones admitidas en objetos JavaScript simples envueltos en jQuery son: .data () ,. prop (),. Bind (), .unbind (), .trigger () y .triggerHandler ().

Extendiéndose en la respuesta de jammus, esto es quizás un poco más práctico para largas secuencias de animaciones. Envíe una lista, anime cada una, recursivamente llame a animate nuevamente con una lista reducida. Ejecute una callback cuando todo haya terminado.

La lista aquí es de elementos seleccionados, pero podría ser una lista de objetos más complejos con diferentes parámetros de animación por animación.

Aquí hay un violín

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

Animar múltiples tags secuencialmente

Puede aprovechar las colas de animación incorporadas de jQuery, si solo selecciona una etiqueta como cuerpo para hacer colas globales:

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

Entonces, aquí está el por qué esto funciona, y lo que está haciendo:

  1. La llamada a $.globalQueue.queue() solo está haciendo una llamada en cola a la animación de su etiqueta, pero la pone en cola en la etiqueta del cuerpo.

  2. Cuando jQuery golpea la animación de tu etiqueta en la cola del cuerpo, la animación de tu etiqueta comienza, en la cola de tu etiqueta, pero por la forma en que funciona el marco de animación jQuery, cualquier callback personalizada provoca que la cola de animación de una etiqueta (la del cuerpo en este caso) se detenga. , hasta que la animación personalizada llame a la función dequeue() . Entonces, aunque las colas para su etiqueta y cuerpo animados están separadas, la cola de la etiqueta del cuerpo ahora está esperando que se dequeue() . http://api.jquery.com/queue/#queue-queueName-callback

  3. Simplemente hacemos que el último elemento en cola en la cola de la etiqueta sea una llamada para continuar la cola global llamando a su función dequeue() – eso es lo que une las colas.

  4. Para mayor comodidad, el método globalQueue.queue devuelve una referencia para facilitar el encadenamiento.

setInterval

En aras de la exhaustividad, es fácil aterrizar aquí buscando una alternativa a setInterval , es decir, no estás buscando coordinar las animaciones por separado, ya que simplemente las disparas con el tiempo sin el extraño surgimiento de tu animación causado por la De esta manera, los navegadores más nuevos pospondrán las colas de animación y los temporizadores para ahorrar CPU.

Puede reemplazar una llamada a setInterval así:

 setInterval(doAthing, 8000); 

Con este:

 /** * 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/

Y evite esas torpes explosiones de animación cuando el navegador vuelve a habilitar sus animaciones en una pestaña de fondo.

También puede poner sus efectos en la misma cola, es decir, la cola del elemento BODY.

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

Asegúrese de llamar a dequeue () dentro de la última callback de efecto.

Esto ya se ha respondido bien (creo que la respuesta de Jammus es la mejor), pero pensé que ofrecería otra opción basada en cómo hago esto en mi sitio web, usando la función de 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"); }); 

(reemplace 1000 con la velocidad de animación deseada. La idea es que la función de retardo se retrasa en esa cantidad y acumula el retraso en la animación de cada elemento, por lo que si sus animaciones fueron cada 500 milisegundos, sus valores de retraso serían 500, 1000, 1500)

editar: La velocidad “lenta” de FYI jquery también es de 600 milisegundos. por lo tanto, si desea utilizar “lento” en sus animaciones, simplemente use estos valores en cada llamada posterior a la función de demora – 600, 1200, 1800

Use la opción de 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" }); });