jQuery:减少触发 mousemove 事件的频率

发布于 2024-10-11 06:04:01 字数 632 浏览 13 评论 0原文

我正在尝试找出一种简洁的方法来聚合 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 插件是您真正需要的!

I'm trying to figure out a clean way to aggregate mousemove events so that I ensure my code gets called, but only once every 250-300 milliseconds.

I've thought about using something like the following, but was wondering if there was a better pattern, or something jQuery provides that will do the same thing:

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

EDIT: The accepted answer below would work perfectly for this situation, however, I found that the mousestop() functionality provided in the answer actually eliminated my need for the aggregation, so if you're reading this question and looking for an answer, see if the mousestop plugin is what you really need!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

夜无邪 2024-10-18 06:04:01

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

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

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

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

After I tried the solution in the accepted answer, I found out that if the mouse keep moving constantly, especially in circular motion, mousemove() event is fired continuously, but the mouse coordinates remain the same.
So I came up with a simpler solution which eliminates mousestop() and setTimeout.

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

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

This will correctly call handleMouseMove() approximately every 100ms. (Note that I said approximately because time delays and intervals in JavaScript is not real-time guaranteed)

酷炫老祖宗 2024-10-18 06:04:01

您的代码很好,只是您应该清除超时,然后再将其设置为 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;
});

Your code is fine except that you should clear the timeout before setting it to null or it might leak:

window.clearTimeout(mousemove_timeout);
mousemove_timeout = null;

As an alternative you could use mousemove/mousestop in conjunction with 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;
});
2024-10-18 06:04:01

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

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

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

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

function foo() {
    //...
}

A solution and a question^^

What about this approach without a global var. Is that a suitable solution?

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

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

function foo() {
    //...
}
百变从容 2024-10-18 06:04:01

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

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

A simple way of gettin the mouse position in a custom period of miliseconds

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);        
})
赠我空喜 2024-10-18 06:04:01

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

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

You seek code Throttling / Debouncing.

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

Sample from 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);
    };
};
无声无音无过去 2024-10-18 06:04:01

我知道我来晚了一点,但这可能对访问此帖子的人有用,这是我的 2 美分。

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

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

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

I know I'm a little late to the party, but it might be of use to people visiting this thread, here is my 2 cents.

Using the modulus operator and simple number increments, you can throttle the firing rate of your function with minimal performance hit, like so;

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

Additionally, if you're afraid to hit the max integer limit, you can reset the fired variable every X thousand hits (again, using the modulus operator) or by using the mouseout event.

回眸一笑 2024-10-18 06:04:01

这是一个非常有趣的问题。我找到了一种不太黑客的方法来做到这一点,你可以看看这个现场演示以下代码片段的

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

This was a really interesting question. I found a less hackish way to do this on, and you can check out this live demo of the following snippet:

({
    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();
_蜘蛛 2024-10-18 06:04:01

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

var paused = null;

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

You can save a few lines by using the timeout to null the timer:

var paused = null;

$("body").mousemove(function (e) {
    if (!paused){
        /** your code here **/
        paused = setTimeout(function(){paused=null}, 250);
    }
});
花辞树 2024-10-18 06:04:01

为什么不使用 setInterval() 代替超时?

Why not use setInterval() instead of timeouts?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文