2009-07-07 14 views
25

Tengo varias funciones para hacer diferentes animaciones a diferentes partes del HTML. Me gustaría encadenar o poner en cola estas funciones para que ejecuten las animaciones secuencialmente y no al mismo tiempo.¿Cómo puedo encadenar o poner en cola funciones personalizadas usando JQuery?

Estoy intentando automatizar múltiples eventos en secuencia para que parezca que un usuario ha estado haciendo clic en diferentes botones o enlaces.

Probablemente podría hacer esto usando funciones de devolución de llamada pero luego tendría que extraer todas las animaciones de las diferentes funciones y reagruparlas en el patrón correcto.

¿Ayuda la "cola" de jquery? No pude entender el documentation para la cola.

ejemplo, JQuery:

function One() { 
     $('div#animateTest1').animate({ left: '+=200' }, 2000); 
    } 
    function Two() { 
     $('div#animateTest2').animate({ width: '+=200' }, 2000); 
    } 

// Call these functions sequentially so that the animations 
// in One() run b/f the animations in Two() 
    One(); 
    Two(); 

HTML:

<div id="animatetest" style="width:50px;height:50px;background-color:Aqua;position:absolute;"></div> 
    <div id="animatetest2" style="width:50px;height:50px;background-color:red;position:absolute;top:100px;"></div> 

Gracias.

EDITAR: Lo intenté con timers pero pensé que había una mejor manera de hacerlo.

editar # 2:

Voy a ser más específico. Tengo múltiples funciones obligadas a hacer clic en & eventos de desplazamiento en diferentes elementos de la página. Normalmente, estas funciones no tienen nada que ver entre sí (no se refieren entre sí). Me gustaría simular que un usuario pase por estos eventos sin cambiar el código de mis funciones existentes.

+0

Creo que el uso de la funcionalidad de devolución de llamada proporcionada por la función animado es el camino a seguir en esto. – seth

+0

Hay una manera de hacer esto ahora en jquery usando el sistema de promesas. Por favor revisa mi respuesta aquí: http://stackoverflow.com/a/18216474/726239 – Shaunak

Respuesta

37

El código jQuery cola no está tan bien documentada como podría ser, pero la idea básica es la siguiente:

$("#some_element").queue("namedQueue", function() { 
    console.log("First"); 
    var self = this; 
    setTimeout(function() { 
    $(self).dequeue("namedQueue"); 
    }, 1000); 
}); 

$("#some_element").queue("namedQueue", function() { 
    console.log("Second"); 
    var self = this; 
    setTimeout(function() { 
    $(self).dequeue("namedQueue"); 
    }, 1000); 
}); 

$("#some_element").queue("namedQueue", function() { 
    console.log("Third"); 
}); 

$("#some_element").dequeue("namedQueue"); 

Si ejecuta este código, verá "primero" en la consola, una pausa de 1s, vea "Segundo" en la consola, otra pausa de 1s, y finalmente vea "Tercero" en la consola.

La idea básica es que puede tener cualquier número de colas con nombre vinculadas a un elemento. Elimina un elemento de la cola llamando al dequeue. Puede hacerlo usted mismo manualmente tantas veces como desee, pero si desea que la cola se ejecute automáticamente, simplemente puede llamar al dequeue dentro de la función en cola.

Las animaciones en jQuery se ejecutan dentro de una cola llamada fx. Cuando anima un elemento, automáticamente agrega la nueva animación en la cola y las llamadas dequeue si no hay animaciones actualmente en ejecución. Puede insertar sus propias devoluciones de llamada en la cola fx si lo desea; solo tendrá que llamar al dequeue manualmente al final (como con cualquier otro uso de la cola).

+0

$ ('div # myDiv1'). Queue ('fx', fn1); $ ('div # myDiv2'). Queue ('fx', fn2); Observe que se ejecutan en paralelo, no secuencialmente. Por lo tanto, si tiene dos funciones, con animate() en diferentes elementos, también se ejecutarán en paralelo. Por lo tanto, el solo uso de colas no permitirá la ejecución secuencial. – user120242

+0

Si utiliza un objeto global en lugar de selectores individuales antes de la .queue sería – methodin

+0

solo para encadenar funciones con efectos, podemos usar el sistema de promesas, que está implementado my .promise() en jQuery. Consulte la respuesta aquí, por ejemplo: http://stackoverflow.com/a/18216474/726239 – Shaunak

0

En lo que a intervalos de animación ya definido en 2000 ms, se puede hacer la segunda llamada con retraso en 2000 ms:

One(); 
SetTimeout(function(){ 
    Two(); 
}, 2000); 
+0

Sé que puedo usar temporizadores o setTimeout, pero pensé que había algún tipo de cola en la que podría poner mis funciones. – orandov

+0

... y no preocuparse por el tiempo. – trusktr

2

Suponiendo que desea mantener One y Two como funciones separadas, se podría hacer algo de esta manera:

function One(callback) { 
    $('div#animateTest1').animate({ left: '+=200' }, 2000, 
     function(e) { callback(); }); 
} 
function Two() { 
    $('div#animateTest2').animate({ width: '+=200' }, 2000); 
} 

// Call these functions sequentially so that the animations 
// in One() run b/f the animations in Two() 
    One(Two); 
+0

¿Qué pasaría si el parámetro de devolución de llamada que se pasó es 'nulo'? ¿Seguiría funcionando? – orandov

+0

No, deberías dominar el manejo de errores allí. Escribí esto en el cuadro de edición de SO, no he pensado mucho en el manejo de errores o tratando de ejecutarlo. – marcc

+0

No estaba tratando de criticar tus habilidades de manejo de errores. :) Estaba preguntando b/c cuando las funciones serán llamadas por el usuario real en realidad haga clic en el enlace no debería haber devolución de llamada (nulo). Solo cuando el código automatice los pasos, será necesario realizar una devolución de llamada. – orandov

2

correría el segundo como una función de devolución de llamada:

$('div#animateTest1').animate({ left: '+=200' }, 2000, function(){ 
    two(); 
}); 

que se ejecutarían dos() cuando termine la primera animación, si tiene más animaciones en la cola temporizada para esos casos, yo uso jquery timer plugin en lugar de setTimeout(), que en algunos casos resulta muy útil.

+0

¿Qué pasa con setTimeout? y ¿cómo funciona ese complemento mejor si internamente utiliza dicho setTimeout? – redsquare

+0

@redsquare $ .animate ya crea un temporizador, ¿por qué no mantener seco su código y usarlo en su lugar? No es necesario hacer múltiples temporizadores. –

3

Creé una serie de funciones y agregué todas las funciones que desea poner en cola.

Luego anexaré una llamada a la función que recorre la matriz y llama cada función al evento a través de jQuery.

Probablemente puedas crear un plugin muy simple para jQuery que también pueda manejar esto internamente.

+0

Creo que su idea se romperá si la función que se va a poner en cola es asincrónica y si el autor desea esperar que la función asíncrona espere antes de ejecutar la siguiente función en la lista. – SolutionYogi

2

En uno de mis proyectos web, tuve que realizar varias secuencias de acciones según el evento desencadenado. Lo hice usando devoluciones de llamada (algo así como el patrón Visitor). Creé un objeto para envolver cualquier función o grupo de acciones. Luego pondría en cola esas envolturas; una matriz funciona bien.Cuando el evento se disparaba, repetía la matriz, llamando al método especializado de mi objeto que recibía una devolución de llamada. Esa devolución de llamada activó mi iteración para continuar.

Para ajustar una función, necesita conocimiento de the apply function. La función aplicar toma un objeto para el alcance y una matriz de argumentos. De esta forma, no necesita saber nada sobre las funciones que está ajustando.

0

El siguiente trabajo y no devolución de llamada de error si es nulo:

function One(callback) 
{ 
    $('div#animateTest1').animate({ left: '+=200' }, 2000, 
     function() 
     { 
      if(callback != null) 
      { 
       callback(); 
      } 
     } 
    ); 
} 
function Two() 
{ 
    $('div#animateTest2').animate({ width: '+=200' }, 2000); 
} 

var callback = function(){ Two(); }; 
One(callback); 
0

tiene que adjuntar @TrippRitter .call a la devolución de llamada

One = function(callback){ 
    $('div#animateTest1').animate({ left: '+=200' }, 2000, function(){ 
     if(typeof callback == 'function'){ 
      callback.call(this); 
     } 
    }); 
} 

Two = function(){ 
    $('div#animateTest2').animate({ width: '+=200' }, 2000); 
} 

One(function(){ 
    Two(); 
}); 

pero su es lo mismo que hacer la siguiente

$('div#animateTest1') 
    .animate({ left: '+=200' }, 2000, 
    function(){ 
     Two(); 
    }); 

Two = function(){ 
    $('div#animateTest2').animate({ width: '+=200' }, 2000); 
} 
-1

En lugar de crear una función de manera simple está aquí:

$('#main').animate({ "top": "0px"}, 3000, function() 
    { $('#navigation').animate({ "left": "100px"}, 3000, function() 
     { 
      alert("Call after first and second animation is completed."); 
     }) 
    } 
); 

Por lo tanto, Jquery proporciona de forma predeterminada la cola que ejecuta la función una por una.

+0

Eso no responde la pregunta. La pregunta requiere que uses dos funciones separadas. No siempre encadenas animaciones juntas, a veces uno puede encadenar funciones personalizadas. – trusktr

1

Una manera más segura y 100% de trabajo es usar una variable y ramas if. En el siguiente ejemplo hacemos 4 trabajos que demoran 1 segundo, después del trabajo que queremos que ejecute la función f2.

<html><body> 
<div id="a" class="a" /> 
<script type="text/javascript"> 
var jobs = 0; 
function f1() { 
job(); 
job(); 
job(); 
job();  
}; 

function f2() { 
    if(jobs >3) 
     l("f2"); 
}; 

<!------------------------- -> 
function job() { 
    setTimeout(function() { 
     l("j"); 
     jobs+=1; 
     f2(); 
    }, 1000); 
} 
function l(a) { 
    document.getElementById('a').innerHTML+=a+"<br />"; 
}; 
f1(); 


</script></body></html> 
1

Really Simple Fix.

function One() { 
     $('div#animateTest1').animate({ left: '+=200' }, 2000, Two); 
    } 
    function Two() { 
     $('div#animateTest2').animate({ width: '+=200' }, 2000); 
    } 

// Call these functions sequentially so that the animations 
// in One() run b/f the animations in Two() 
    One(); 
//We no longer need to call Two, as it will be called when 1 is completed. 
    //Two(); 
0
$('div#animateTest1').animate({left: '+=200'},2000, 
function(){ 
    $('div#animateTest2').animate({ width: '+=200' }, 2000); 
} 
); 
0

Copiar y pegar ............ 7/9/2013

<!doctype html> 
<html lang="en"> 
    enter code here<head> 
    <meta charset="utf-8"> 
    <title>jQuery.queue demo</title> 
    <style> 
    div { margin:3px; width:40px; height:40px; 
     position:absolute; left:0px; top:30px; 
     background:green; display:none; } 
    div.newcolor { background:blue; } 
    </style> 
    <script src="http://code.jquery.com/jquery-1.9.1.js"></script> 
</head> 
<body> 

    <button id="start">Start</button> 
    <button id="stop">Stop</button> 
    <div></div> 
<script> 
    $("#start").click(function() { 
     $("div").show("slow"); 
     $("div").animate({left:'+=200'},5000); 
     jQuery.queue($("div")[0], "fx", function() { 
     $(this).addClass("newcolor"); 
     jQuery.dequeue(this); 
     }); 
     $("div").animate({left:'-=200'},1500); 
     jQuery.queue($("div")[0], "fx", function() { 
     $(this).removeClass("newcolor"); 
     jQuery.dequeue(this); 
     }); 
     $("div").slideUp(); 
    }); 
    $("#stop").click(function() { 
     jQuery.queue($("div")[0], "fx", []); 
     $("div").stop(); 
    }); 
</script> 

</body> 
</html> 
2

¿Qué tal algo por el estilo?

var f1 = function() {return $(SELECTOR1).animate({ 'prop': 'value' }, 1000)}; 
var f2 = function() {return $(SELECTOR2).animate({ 'prop': 'value' }, 1000)}; 
var f3 = function() {return $(SELECTOR3).animate({ 'prop': 'value' }, 1000)}; 

$.when(f1).then(f2).then(f3); 
0

Si bien la respuesta de Yehuda Katz es técnicamente correcto se hinchan muy rápidamente con animaciones más complejas más grandes.

He hecho un complemento para situaciones como la suya que permite funciones de cola (con pausa y reanudar si es necesario).

demo: https://jessengatai.github.io/okaynowthis.js/

La solución a su problema usando okaynowthis.js se vería así:

$('window').load(function(){ 

    // keyframe 1 
    $('body').okaynowthis('keyframe',0,function(){ 
     $('div#animateTest1').animate({ left: '+=200' }, 2000); 
     // + anything else you want to do 

    // keyframe 2 (with 2 seconds delay from keyframe 1) 
    }).okaynowthis('keyframe',2000,function(){ 
     $('div#animateTest2').animate({ left: '+=200' }, 2000); 
     // + anything else you want to do 

    }); 

}); 
Cuestiones relacionadas