【问题标题】:jQuery: Fire mousemove events less oftenjQuery:不太频繁地触发 mousemove 事件
【发布时间】:2023-04-02 15:11:01
【问题描述】:

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

【问题讨论】:

    标签: jquery settimeout mousemove


    【解决方案1】:

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

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

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

    【讨论】:

    • +1 - 谢谢!这实际上是我最初寻找的解决方案类型。这是一种比公认答案更简洁的方法,但是,mousestop 插件仍然是我使用的。
    • 鼠标不动时有没有办法停止定时器?
    【解决方案2】:

    您的代码很好,只是您应该在将其设置为 null 之前clear the timeout 否则它可能会泄漏:

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

    【讨论】:

    • +1 - 感谢您的提示!这是最好/最干净的方式吗?看起来有点像黑客......
    • 是的,这确实有点像 hack,window.setInterval 会更适合这种情况。
    • 接受! - 事实证明,mousestop 函数正是我所需要的,它将完全消除超时代码。非常感谢!
    • 这种方法有问题:如果鼠标不断移动,mousemove 事件会不断触发,但鼠标坐标保持不变。
    【解决方案3】:

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

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

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

    【讨论】:

    • +1 - 我绝对喜欢不使用全局变量。虽然我没有尝试过这段代码,但它看起来确实相当干净和直观。
    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

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

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

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

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

        【讨论】:

          【解决方案7】:

          这是一个非常有趣的问题。我找到了一种不那么骇人听闻的方法来做到这一点,您可以查看以下 sn-p 的 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();
          

          【讨论】:

            【解决方案8】:

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

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

            【讨论】:

              【解决方案9】:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2019-11-18
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-10-21
                • 1970-01-01
                • 2017-04-29
                • 1970-01-01
                相关资源
                最近更新 更多