2011-09-18 119 views
17

我不知道是否调用这个嵌套是否正确?但是我知道这不是一个很好的代码,它有很多功能。大多数jQuery方法都有回调函数,我们可以将回调函数放在那里。但是当我们在另一个回调中进行回调并继续这个并且越来越深时,它看起来代码变得不太可读并且可能更少可调试。如何防止过多的嵌套函数jQuery代码?

例如,如果我想在彼此之后做一些动画,我必须调用每一个动画,我想要在它的回调函数之后来到另一个动画。它在回调函数中会越来越深入。看下面这个例子(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... 
       }); 
      }); 
     }); 
    }); 
}); 

做一个5个步骤的动画我必须做出一个5级调用堆栈。所以我的问题是你如何避免这种情况?我的Node.js函数也有同样的问题。

更新: 我知道jQuery函数有chinning功能,但不解决问题。因为你无法在连锁店之间做点什么。你可以写上面的代码一样$(selector').animate().animate()...,但你不能为此做相同的:

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

理想的解决办法是这样的代码:

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

但可悲的是jQuery的没有一个API像这样(据我所知)。

+0

我不认为这样的嵌套功能有问题。 – Nathan

+3

@Nathan:真的吗?尝试调试,维护和阅读深层嵌套的代码。 –

+0

@Andrew我的意思是我认为它会起作用。我以为他在问是否合适。是的,调试,阅读和维护非常困难。 – Nathan

回答

23

*“的理想解决方案将是一个这样的代码:

$(选择).doQ(anim1,anim2,myfunc1,anim3,myfunc2所)...“*

这是不太你想要什么,但jQuery也有queue()[docs]方法:

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

你只需要确保你的函数释放队列时,他们所做使用dequeue()[docs]方法:

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

或者你可以用在一个匿名函数的功能,并调用然后出列有:

$(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

this,但myfunc1必须接受'next'参数,并在完成后运行next();否则它将不会继续。 – evan

+0

哈,我也是这么写的)+1 –

+0

@evan:尽管可以使用'.dequeue()'而不是传递的参数,请参阅我的更新。 – user113716

0

你可以做的是同一个名字定义函数,并引用他们另一个函数内部,例如

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

阅读上JQuery的Deferred Object

它是一个可链接的实用对象,可以将多个回调 注册到回调队列中,调用回调队列,并中继任何同步或异步功能的成功或故障状态。

如果您的回调只是动画,那么只需链接它们并利用JQuery的fx队列。

+0

我的问题是关于没有*回叫的情况* ... – Mohsen

7

阅读jQuery队列。您的代码也可以写成这样:

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

第一动画是立即执行,但其他人都戴上了“FX”队列和执行反过来当别人完成。

+0

我更新了我的问题。看一看。我知道如何链接工程... – Mohsen

+0

@Mohsen你可以结合链接方法和回调... – lonesomeday

+0

所以我的问题是如何?! :) – Mohsen

4

jQuery对象有一个默认队列。试试这个小提琴:http://jsfiddle.net/TbkjK/1/

+0

如果你想在两者之间做点什么?看看我更新的问题 – Mohsen

+0

这不是问题的一部分......但是,您可以将动画链接起来,当您想要做额外的事情时有回调,然后在回调中完成连锁。 – gislikonrad

2

小更清洁的方式:

$('#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!"); 
} 

基础上,logCount数量只需做一些事情。例如可以看到here

+0

谢谢你的答案。我不想要一个基于案例的解决方案。我只是为了更好地理解问题而添加示例 – Mohsen