2011-01-10 116 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事件。