jQuery: запускать события мыши меньше - PullRequest
7 голосов
/ 10 января 2011

Я пытаюсь найти чистый способ агрегирования событий перемещения мыши, чтобы гарантировать, что мой код вызывается, но только один раз каждые 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 тебе действительно нужно!

Ответы [ 9 ]

16 голосов
/ 05 января 2012

После того, как я попробовал решение в принятом ответе, я обнаружил, что если мышь продолжает двигаться постоянно, особенно при круговом движении, событие mousemove () запускается непрерывно, но координаты мыши остаются неизменными.Поэтому я пришел к более простому решению, которое исключает mousestop () и setTimeout.

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

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

Это будет правильно вызывать handleMouseMove () примерно каждые 100 мс.(Обратите внимание, что я сказал приблизительно, потому что временные задержки и интервалы в JavaScript не гарантируются в реальном времени)

5 голосов
/ 10 января 2011

Ваш код в порядке, за исключением того, что вы должны очистить тайм-аут перед установкой его на ноль, иначе он может протечь:

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;
});
4 голосов
/ 10 января 2011

Решение и вопрос ^^

А как насчет этого подхода без глобальной вар.Это подходящее решение?

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

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

function foo() {
    //...
}
3 голосов
/ 24 февраля 2013

Простой способ получить положение мыши в произвольный период в миллисекундах

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 голосов
/ 30 декабря 2015

Я знаю, что немного опоздал на вечеринку, но это может быть полезно людям, посещающим эту ветку, вот мои 2 цента.

Используя оператор модуля и простые приращения чисел, вы можете регулировать частоту срабатывания вашей функции с минимальным ударом по производительности, вот так;

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

Кроме того, если вы боитесь достичь максимального целочисленного предела, вы можете сбрасывать сгенерированную переменную каждые X тысяч обращений (опять же, используя оператор модуля) или с помощью события mouseout.

2 голосов
/ 10 сентября 2015

Вы ищете код регулирования / отбрасывания.

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);
    };
};
1 голос
/ 17 августа 2012

Вы можете сохранить несколько строк, используя тайм-аут для обнуления таймера:

var paused = null;

$("body").mousemove(function (e) {
    if (!paused){
        /** your code here **/
        paused = setTimeout(function(){paused=null}, 250);
    }
});
1 голос
/ 10 января 2011

Это был действительно интересный вопрос.Я нашел менее хакерский способ сделать это, и вы можете проверить это живое демо следующего фрагмента:

({
    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();
0 голосов
/ 10 января 2011

Почему бы не использовать setInterval () вместо тайм-аутов?

...