2011-01-10 130 views
7

我想弄清楚一個乾淨的方式來聚合mousemove事件,以便確保我的代碼被調用,但每250-300毫秒只有一次。jQuery:不經常觸發mousemove事件

我已經考慮過使用類似以下,但不知道是否有更好的方式,或者說jQuery提供,將做同樣的事情:

var mousemove_timeout = null; 

$('body').mousemove(function() { 
    if (mousemove_timeout == null) { 
    mousemove_timeout = window.setTimeout(myFunction, 250); 
    } 
}); 

function myFunction() { 
    /* 
    * Run my code... 
    */ 

    mousemove_timeout = null; 
} 

編輯:接受的答案下面這種情況完全適用於這種情況,但是,我發現回答中提供的mousestop()功能實際上消除了我對聚合的需求,所以如果您正在閱讀此問題並尋找答案,請參閱mousestop插件是否是您真的需要!

回答

5

你的代碼是除了罰款,你應該clear the timeout將其設置爲空或可能泄漏前:

window.clearTimeout(mousemove_timeout); 
mousemove_timeout = null; 

正如你可以結合使用鼠標移動/ mousestopwindow.setInterval

var timer = null; 
var isIntervalSet = false; 

$('body').mousemove(function() { 
    if (isIntervalSet) { 
     return; 
    } 
    timer = window.setInterval(function() { 
     /* 
     * Run my code... 
     */  
    }, 250); 
    isIntervalSet = true; 
}).mousestop(function() { 
    isIntervalSet = false; 
    window.clearTimeout(timer); 
    timer = null; 
}); 
+0

+1 - 感謝您的提示!這是最好的/最乾淨的方式嗎?看起來像一個黑客... – 2011-01-10 15:44:11

+1

是的,這確實是一個黑客,`window.setInterval`會更適應這種情況。 – 2011-01-10 15:49:41

+0

接受! - 原來,`mousestop`函數正是我所需要的,並且完全消除了超時代碼。非常感謝! – 2011-01-10 16:02:58

4

替代一個解決方案和一個問題^^

這種方法怎麼樣,沒有一個全球變種。這是一個合適的解決方案?

$(function() { 
    $("#foo").mousemove((function() { 
     var timer = null; 

     return function() { 
      if (timer !== null) { 
       window.clearTimeout(timer); 
      } 
      timer = window.setTimeout(foo, 250); 
     }; 
    })()); 
}); 

function foo() { 
    //... 
} 
1

這是一個非常有趣的問題。我發現了一個更小的hackish辦法做到這一點上,你可以看看這個live demo下面的代碼片斷的:

({ 
    event: null, 
    interval: null, 
    init: function(){ 
     var self = this; 
     $(document).bind("mousemove", function(e){self.event=e;}); 
     this.interval = setInterval(function(){ 
      /** do what you wish **/ 
      console.log(self.event); 
     }, 250); 
     return this; 
    }, 
    stop: function(){ 
     $(document).unbind("mousemove", this.event); 
     clearInterval(this.interval); 
    }, 
}).init(); 
16

我試着在接受答案的解決方案之後,我發現,如果鼠標繼續不停地移動,特別是在圓周運動中,mousemove()事件不斷被觸發,但鼠標座標保持不變。 所以我想出了一個簡單的解決方案,它消除了mousestop()和setTimeout。

$("body").mousemove(function (e) { 
     if (enableHandler) { 
      handleMouseMove(e); 
      enableHandler = false; 
     } 
}); 

timer = window.setInterval(function(){ 
    enableHandler = true; 
}, 100); 

這將正確地調用handleMouseMove()大約每100ms。 (請注意,我約說,由於在JavaScript中的時間延遲,時間間隔不是實時的保證)

1

您可以通過使用超時節省幾行空計時器:

var paused = null; 

$("body").mousemove(function (e) { 
    if (!paused){ 
     /** your code here **/ 
     paused = setTimeout(function(){paused=null}, 250); 
    } 
}); 
3

的一種簡單方法在一個自定義的毫秒時間內獲取鼠標位置

var timer; 
var refresh_time = 50; 
var x = 0; 
jQuery('body').mousemove(function(evt) { 
    if (timer) 
    clearTimeout(timer); 
    timer = setTimeout(function(){ 
     var mouse_x = evt.clientX; 
     if(mouse_x != x){ 
     x = mouse_x; 
     console.log('mouse is on a new x position' + x);  
     } 
    }, refresh_time);   
}) 
2

您尋求代碼調節/去抖動。

http://benalman.com/projects/jquery-throttle-debounce-plugin/ http://drupalmotion.com/article/debounce-and-throttle-visual-explanation

從下劃線樣品。JS

// Returns a function, that, as long as it continues to be invoked, will not 
// be triggered. The function will be called after it stops being called for 
// N milliseconds. If `immediate` is passed, trigger the function on the 
// leading edge, instead of the trailing. 
function debounce(func, wait, immediate) { 
    var timeout; 
    return function() { 
     var context = this, args = arguments; 
     var later = function() { 
      timeout = null; 
      if (!immediate) func.apply(context, args); 
     }; 
     var callNow = immediate && !timeout; 
     clearTimeout(timeout); 
     timeout = setTimeout(later, wait); 
     if (callNow) func.apply(context, args); 
    }; 
}; 
1

我知道我有點遲到了,但也可能是使用的人訪問這個線程,這裏是我的2美分。

使用模運算符和簡單數字增量,可以用最小的性能命中來調節函數的點火速率,就像這樣;

var fired = 0; 
$('#element').on('mousemove', function(){ 
    fired++; 
    // Fire 5x less than usual 
    if(!(fired % 5) || fired == 1) yourFunction(); 
}) 

此外,如果你害怕撞到最大整數限制,你可以重新燒製的變量每X千次點擊(再次使用模運算符)或使用mouseout事件。