8

我试图找出一种干净的方法来聚合 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()答案中提供的功能实际上消除了我对聚合的需要,所以如果您正在阅读这个问题并寻找答案,请查看mousestop插件是你真正需要的!

4

9 回答 9

18

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

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

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

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

于 2012-01-05T14:22:07.330 回答
5

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

window.clearTimeout(mousemove_timeout);
mousemove_timeout = null;

作为替代方案,您可以将 mousemove/ 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;
});
于 2011-01-10T15:37:52.490 回答
4

一个解决方案和一个问题^^

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

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

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

function foo() {
    //...
}
于 2011-01-10T15:47:49.243 回答
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);        
})
于 2013-02-23T20:20:54.380 回答
2

您寻求代码节流/去抖动。

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);
    };
};
于 2015-09-10T13:25:23.090 回答
2

我知道我参加聚会有点晚了,但它可能对访问此线程的人有用,这是我的 2 美分。

使用模数运算符和简单的数字增量,您可以在对性能影响最小的情况下限制函数的触发率,如下所示;

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

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

于 2015-12-30T14:38:12.330 回答
1

这是一个非常有趣的问题。我找到了一种不那么骇人听闻的方法来执行此操作,您可以查看以下代码段的现场演示:

({
    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();
于 2011-01-10T16:13:53.550 回答
1

您可以通过使用超时将计时器设为空来节省几行:

var paused = null;

$("body").mousemove(function (e) {
    if (!paused){
        /** your code here **/
        paused = setTimeout(function(){paused=null}, 250);
    }
});
于 2012-08-17T17:47:08.833 回答
0

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

于 2011-01-10T15:51:20.303 回答