2015-03-08 37 views
1

我寫了一個自定義動畫函數。它通常工作得很好,但是當我用不同的endCallbacks快速連續呼叫animate();時,有時候回調會非常糟糕,導致在錯誤的時間進行錯誤的操作。如果多次調用同一函數的前一個實例,該如何停止?

問題是函數實例化多次並執行直到達到endValue。 currentValue被改變得非常快,以至於我只能看到我的html頁面動畫中的最後一個值。這隱藏了這種不需要的行爲。

我第二次撥打animate();時需要的是結束animate();的第一個實例,並用新值和新回調觸發一個新實例。同時我也想停止setTimeout()函數,以確保沒有錯誤的回調被觸發。

window.onload = function(){ 
    document.addEventListener('click', // some button 
     function(){ 
      animate(1, 10); 
     }, false 
    ); 
} 

function animate(startValue, endValue, callback, endCallback) { 
    var startValue = startValue, 
     currentValue = startValue, 
     endValue = endValue, 
     callback = callback, 
     timeout = null; 

    loopAnimation(); 
    function loopAnimation(){ 
     if (currentValue != endValue){ 
      timeout = setTimeout(function(){ 
       currentValue++; 

       // Callback executes some page manipulation code 
       if (typeof callback !== "undefined") callback(currentValue); 
       console.log(currentValue); 
       loopAnimation(); 
      },500) 
     } else { 
      console.log("This callback triggers some specific changes in my page"); 
      if (typeof endCallback !== "undefined") endCallback(); 
     } 
    } 
} 

而是在控制檯中看到的: 1,2,3, - 1,4,2,5 ...... 6,9,7,10,8,9,10

我'd喜歡看: 1,2,3, - 1,2 ... 7,8,9,10

但請記住,由於我在腳本中使用animate()的方式,我可以絕對不要了解輸入變量的名稱或範圍。這使我無法自己解決它。

+1

你不能阻止一個功能從另一個執行。假設您正在使用jquery進行動畫,您可以調用一個'.stop'方法來停止在該元素上運行的所有動畫。 http://api.jquery.com/stop/ – lwalden 2015-03-08 21:35:58

回答

1

雖然它不是您要求的實現,但我不知道Underscore的節流或去抖動能否滿足需求?

debounce將確保您的函數每秒被調用不超過X次 - 每調用一次它仍會執行一次,但隨後的調用將被延遲以滿足您的速率限制。所以,如果你連續快速地調用動畫兩次,去抖動可以延遲第二次執行,直到第一次或你之後的100ms。

throttle基本上會忽略速率限制期間發生的呼叫。所以如果你在100ms內調用你的動畫10次,你可以把它扔掉,除了第一次。 (實際上,它將在等待期結束時完成第一個,另外一個)。

您不需要使用所有的下劃線來獲得這些方法;我已經看到人們經常複製和粘貼下劃線的反彈和/或油門功能。如果你是谷歌,你可以找到一些獨立的油門或反彈實施。

油門和去抖動通常用於你的情況,動畫。

對於你的原始規範,實際上「結束animate()的第一個實例」 - 在JavaScript中沒有很好的可靠方法來做到這一點。沒有真正的通用方法來「取消」已經執行的功能。如果你能使它反彈或節流,我認爲它會減少挫折感。

+0

我需要能夠隨時更改動畫對象的狀態,因此防止雙擊它不是我的目的的真正選擇。乾杯! – 2015-03-09 08:30:53

0

你需要的是存儲你使用的最後一個超時ID。因此,下次啓動新動畫時,請使用此超時ID和clearTimeout清除正在進行的動畫。
我發現很方便在函數本身上存儲間隔。

在這裏看到的jsbin: http://jsbin.com/nadawezete/1/edit?js,console,output

window.onload = function(){ 
    document.addEventListener('click', // some button 
     function(){ 
      animate(1, 10); 
     }, false 
    ); 
}; 

function animate(startValue, endValue, callback, endCallback) { 
    var currentValue = startValue; 
    if (animate.timeout) clearTimeout(animate.timeout); 
    loopAnimation(); 
    function loopAnimation(){ 
     if (currentValue != endValue){ 
      animate.timeout = setTimeout(function(){ 
       console.log(currentValue); 
       currentValue++;  
       // Callback executes some page manipulation code 
       if (callback) callback(currentValue); 
       loopAnimation(); 
      },500); 
     } else { 
      console.log("This callback triggers some specific changes in my page"); 
      if (endCallback) endCallback(); 
     } 
    } 
} 
+0

這與我所尋找的非常接近。對於我的具體用例,它工作得很好,我可以通過創建一個擁有多個setTimeout()的對象來進一步調整這個解決方案。用於多個動畫變量的ID。這將有助於動畫化不同的對象,而無需重新設置錯誤對象的動畫。非常感謝你! – 2015-03-09 08:35:14

+0

不客氣!所以你似乎可以接受這個答案。請注意,如果您執行「很多」(20+以上)的動畫,setTimeout開銷可能會因您的問題而變得太大。您必須恢復邏輯,並在setInterval或requestAnimationFrame上掛接單個處理程序,以驅動所有動畫邏輯。 – GameAlchemist 2015-03-09 08:57:10

+0

在我目前的項目中,我使用requestAnimationFrame();對於多個畫布和頁面操作,事實上,它確實通過明顯的措施提高了整體性能。爲了使不需要的行爲容易被注意,我簡化了示例代碼。我將替換clearTimeout();與cancelAnimationFrame();非常感謝您的反饋! – 2015-03-09 09:39:58

相關問題