jQuery:不常用火鼠移动事件

我试图找出一种简洁的方法来聚合mousemove事件,以便我确保我的代码被调用,但每250-300毫秒只能调用一次。

我曾考虑使用类似下面的内容,但想知道是否有更好的模式,或者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()function实际上消除了我对聚合的需求,所以如果你正在阅读这个问题并寻找答案,请参阅如果mousestop插件是你真正需要的!

您的代码很好,除非您应该在将其设置为null之前清除超时 ,否则它可能会泄漏:

 window.clearTimeout(mousemove_timeout); mousemove_timeout = null; 

作为替代方案,您可以将mousemove / mousestop与window.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; }); 

在我接受的答案中尝试了解决方案之后,我发现如果鼠标不断移动,特别是在圆周运动中,则会连续触发mousemove()事件,但鼠标坐标保持不变。 所以我提出了一个更简单的解决方案,它消除了mousestop()和setTimeout。

 $("body").mousemove(function (e) { if (enableHandler) { handleMouseMove(e); enableHandler = false; } }); timer = window.setInterval(function(){ enableHandler = true; }, 100); 

这将大约每100毫秒正确调用handleMouseMove()。 (请注意,我说大约是因为JavaScript中的时间延迟和间隔不是实时保证)

解决方案和问题^^

没有全局变量的这种方法怎么样? 这是一个合适的解决方案?

 $(function() { $("#foo").mousemove((function() { var timer = null; return function() { if (timer !== null) { window.clearTimeout(timer); } timer = window.setTimeout(foo, 250); }; })()); }); function foo() { //... } 

一种在自定义的毫秒时间内获得鼠标位置的简单方法

 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); }) 

您寻求代码限制/去债。

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

来自underscore.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); }; }; 

这是一个非常有趣的问题。 我找到了一种不那么强硬的方法来执行此操作,您可以查看以下代码段的实时演示

 ({ 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(); 

您可以使用超时来保存几行,以使计时器为空:

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

我知道我参加派对有点晚了,但对于访问这个post的人来说,这可能是有用的,这是我的2美分。

使用模数运算符和简单的数字增量,您可以以最小的性能命中来限制函数的激发率,就像这样;

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

此外,如果您害怕达到最大整数限制,则可以每X千次点击(再次使用模数运算符)或使用mouseout事件重置已触发的变量。

为什么不使用setInterval()而不是超时?