2011-09-18 64 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