2011-09-18 12 views
17

No sé si llamar a este anidando es correcto o no? Pero sé que no es un buen código para tener muchas funciones dentro de los demás. La mayoría de los métodos jQuery tienen función de devolución de llamada que podemos poner nuestras devoluciones de llamada allí. Pero cuando hacemos devoluciones de llamada dentro de otra devolución de llamada y continuamos esto y vamos más y más profundo parece que el código se vuelve menos legible y quizás menos depurable.¿Cómo prevenir el código jQuery de demasiadas funciones de anidamiento?

Por ejemplo, si quiero hacer algunas animaciones una detrás de otra, tengo que llamar a cada animación que quiero que aparezca después de otra en su función de devolución de llamada. Se irá profundizando en la función de devolución de llamada. Mira este ejemplo (fiddle):

$('#t').animate({height: 400}, 500, function(){ 
    $(this).animate({height: 200}, 500, function(){ 
     $(this).animate({width: 300}, 500, function(){ 
      $(this).animate({height: 300}, 500, function(){ 
       $(this).animate({'border-radius': '50px'}, 500, function(){ 
        //and so on... 
       }); 
      }); 
     }); 
    }); 
}); 

para hacer una animación de 5 pasos que tengo que hacer una pila de llamadas de 5 niveles. ¿Entonces mi pregunta es cómo evitar esto? Tuve el mismo problema en mis funciones de Node.js también.

Actualización: Sé que la función jQuery tiene la función de lomo, pero eso no resuelve el problema. porque no puedes hacer algo en el medio de la cadena. Se podría escribir por encima de código como $(selector').animate().animate()... pero no se puede hacer igual para esto:

$('#t').animate({height: 400}, 500, function(){ 
     console.log('step 1 done: like a boss'); 
     $(this).animate({height: 200}, 500, function(){ 
      console.log('step 2 done: like a boss'); 
      $(this).animate({width: 300}, 500, function(){ 
       console.log('step 3 done: like a boss'); 
       $(this).animate({height: 300}, 500, function(){ 
        console.log('step 4 done: like a boss'); 
        $(this).animate({'border-radius': '50px'}, 500, function(){ 
         //and so on... 
        }); 
       }); 
      }); 
     }); 
    }); 

La solución ideal sería un código como el siguiente:

$(selector).doQ(anim1, anim2, myfunc1, anim3, myfunc2)... 

Pero, lamentablemente jQuery no tienen una API como este (que yo sepa).

+0

No creo que haya un problema con las funciones de anidamiento como esa. – Nathan

+3

@Nathan: ¿De verdad? Intenta depurar, mantener y leer el código que está anidado tan profundo. –

+0

@Andrew Quiero decir, creo que funcionará. Pensé que estaba preguntando si es correcto o no. Y sí, es muy difícil de depurar, leer y mantener. – Nathan

Respuesta

23

* "La solución ideal sería un código como el siguiente:

$ (selector) .doQ (anim1, anim2, MyFunc1, anim3, myfunc2) ..."*

Esto no es exactamente lo que quiere, pero jQuery tiene la queue()[docs] método:

$(selector).animate({height: 400}, 500) 
      .animate({height: 200}, 500) 
      .queue(myfunc1) 
      .animate({width: 300}, 500) 
      .queue(myfunc2); 

Sólo tiene que asegurarse de que sus funciones liberan la cola y cuando estén listas por utilizando el método de dequeue()[docs]:

function myfunc1() { 
    // your code 
    $(this).dequeue(); 
} 

O puede envolver sus funciones en una función anónima, e invocar a continuación, quitar de la cola que hay:

$(selector).animate({height: 400}, 500) 
      .animate({height: 200}, 500) 
      .queue(function(nxt) { 
       myfunc1(); 
       $(this).dequeue(); 
      }) 
      .animate({width: 300}, 500) 
      .queue(function(nxt) { 
       myfunc2(); 
       nxt(); // alternate way to dequeue 
      }); 
+0

esto, pero myfunc1 debe tomar un argumento 'next' y ejecutar' next(); 'cuando esté listo o no continuará. – evan

+0

Ha, yo también escribí eso;) +1 –

+0

@evan: Vea mis actualizaciones, aunque puede usar '.dequeue()' en lugar del argumento pasado. – user113716

0

lo que puede hacer es definir funciones con un nombre, y hacer referencia a ellos dentro de otra función, por ejemplo

var clicka = function(){ 
    alert("I got clicked after t.") 
    } 
    var clickt = function(){ 
     alert("I got clicked!") 
     $('#a').click(clicka) 
    } 
    $('#t').click(clickt); 
4

leer sobre de Deferred Object

Es un objeto de utilidad de conexión en cadena que puede jQuery registre múltiples devoluciones de llamada en colas de devolución de llamada, invoque colas de devolución de llamada y retransmita el estado de falla o de cualquier función síncrona o asíncrona.

Si sus devoluciones de llamada son ÚNICAMENTE animación, simplemente conéctelas y utilice la cola fx de JQuery.

+0

Mi pregunta es acerca de la situación de que no hay * solo devolución de llamada * ... – Mohsen

7

Lectura en colas jQuery. El código también podría escribirse así:

$('#t') 
    .animate({height: 400}, 500) 
    .animate({height: 200}, 500) 
    .animate({width: 300}, 500) 
    .animate({height: 300}, 500) 
    .animate({'border-radius': '50px'}, 500); 

La primera animación se ejecuta inmediatamente, pero los demás se ponen en la cola "fx" y ejecutado a su vez, cuando los demás terminen.

+0

He actualizado mi pregunta. Echar un vistazo. Sé cómo funciona el encadenamiento ... – Mohsen

+0

@Mohsen Puedes combinar el enfoque de encadenamiento y las devoluciones de llamada ... – lonesomeday

+0

así que mi pregunta es CÓMO? :) – Mohsen

4

Los objetos jQuery tienen una cola predeterminada. Prueba este violín: http://jsfiddle.net/TbkjK/1/

+0

¿Qué sucede si quieres hacer algo mientras tanto? Mira mi pregunta actualizada – Mohsen

+0

Que nunca fue parte de la pregunta ... Sin embargo, puedes encadenar las animaciones, tener una devolución de llamada cuando quieras hacer algo extra, luego terminar la cadena en la devolución de llamada. – gislikonrad

2

Un poco más limpio:

$('#t') 
    .animate({height: 400}, 500, animationDone) 
    .animate({height: 200}, 500, animationDone) 
    .animate({width : 200}, 500, animationDone) 
    .animate({height: 300}, 500, animationDone) 
    .animate({'border-radius': '50px'}, 500, animationDone); 


var logCount = 0; 
function animationDone(e) { 
    logCount++; 

    $("#t").html("Animation # " + logCount + " has completed!"); 
} 

Basta con hacer algo basado en el número logCount. El ejemplo se puede ver here.

+0

Gracias por la respuesta. No quería una solución basada en casos. Solo agrego el ejemplo para una mejor comprensión de la pregunta – Mohsen

Cuestiones relacionadas