Как отложить обработчик .keyup (), пока пользователь не перестанет печатать? - PullRequest
591 голосов
/ 15 декабря 2009

У меня есть поле поиска. Прямо сейчас он ищет все ключи. Поэтому, если кто-то наберет «Windows», он выполнит поиск с помощью AJAX для каждого ключа: «W», «Wi», «Win», «Wind», «Windo», «Window», «Windows».

Я хочу иметь задержку, поэтому поиск выполняется только тогда, когда пользователь перестает печатать в течение 200 мс.

Для этой функции нет функции keyup, и я пробовал setTimeout, но она не работала.

Как я могу это сделать?

Ответы [ 25 ]

5 голосов
/ 17 декабря 2012

Я удивлен, что никто не упомянул проблему с множественным вводом в CMS.

По сути, вам придется определять переменную задержки индивидуально для каждого входа. В противном случае, если sb поместит текст в первый ввод и быстро перейдет к другому вводу и начнет печатать, будет вызван обратный вызов для первого НЕ !

См. Код ниже, с которым я пришел, основываясь на других ответах:

(function($) {
    /**
     * KeyUp with delay event setup
     * 
     * @link /920805/kak-otlozhit-obrabotchik-keyup-poka-polzovatel-ne-perestanet-pechatatanswer-12581187
     * @param function callback
     * @param int ms
     */
    $.fn.delayKeyup = function(callback, ms){
            $(this).keyup(function( event ){
                var srcEl = event.currentTarget;
                if( srcEl.delayTimer )
                    clearTimeout (srcEl.delayTimer );
                srcEl.delayTimer = setTimeout(function(){ callback( $(srcEl) ); }, ms);
            });

        return $(this);
    };
})(jQuery);

Это решение сохраняет ссылку setTimeout внутри переменной inputTimer. Он также передает ссылку на элемент в функцию обратного вызова, как предложил fazzyx.

Протестировано в IE6, 8 (comp - 7), 8 и Opera 12.11.

4 голосов
/ 29 июня 2012

Функция задержки для вызова при каждом включении. JQuery 1.7.1 или выше требуется

jQuery.fn.keyupDelay = function( cb, delay ){
  if(delay == null){
    delay = 400;
  }
  var timer = 0;
  return $(this).on('keyup',function(){
    clearTimeout(timer);
    timer = setTimeout( cb , delay );
  });
}

Использование: $('#searchBox').keyupDelay( cb );

3 голосов
/ 09 декабря 2017

Опираясь на ответ CMS, вот новый метод задержки, который сохраняет «this» в своем использовании:

var delay = (function(){
  var timer = 0;
  return function(callback, ms, that){
    clearTimeout (timer);
    timer = setTimeout(callback.bind(that), ms);
  };
})();

Использование:

$('input').keyup(function() {
    delay(function(){
      alert('Time elapsed!');
    }, 1000, this);
});
2 голосов
/ 19 августа 2013

Основываясь на ответе CMS, он просто игнорирует ключевые события, которые не меняют значение.

var delay = (function(){
    var timer = 0;
    return function(callback, ms){
      clearTimeout (timer);
      timer = setTimeout(callback, ms);
    };
})(); 

var duplicateFilter=(function(){
  var lastContent;
  return function(content,callback){
    content=$.trim(content);
    if(content!=lastContent){
      callback(content);
    }
    lastContent=content;
  };
})();

$("#some-input").on("keyup",function(ev){

  var self=this;
  delay(function(){
    duplicateFilter($(self).val(),function(c){
        //do sth...
        console.log(c);
    });
  }, 1000 );


})
2 голосов
/ 15 декабря 2009

Использование

mytimeout = setTimeout( expression, timeout );

где expression - это скрипт, который нужно запустить, а timeout - это время ожидания в миллисекундах, прежде чем он запустится - это НЕ повреждает скрипт, а просто задерживает выполнение этой части, пока не истечет тайм-аут.

clearTimeout(mytimeout);

сбросит / очистит тайм-аут, чтобы он не запускал скрипт в выражении (например, отмена), если он еще не был выполнен.

2 голосов
/ 17 июля 2013

Это решение, аналогичное CMS, но решающее для меня несколько ключевых вопросов:

  • Поддерживает несколько входов, задержки могут выполняться одновременно.
  • Игнорирует ключевые события, которые не изменили значение (например, Ctrl, Alt + Tab).
  • Решает условие гонки (когда обратный вызов выполнен и значение уже изменено).
var delay = (function() {
    var timer = {}
      , values = {}
    return function(el) {
        var id = el.form.id + '.' + el.name
        return {
            enqueue: function(ms, cb) {
                if (values[id] == el.value) return
                if (!el.value) return
                var original = values[id] = el.value
                clearTimeout(timer[id])
                timer[id] = setTimeout(function() {
                    if (original != el.value) return // solves race condition
                    cb.apply(el)
                }, ms)
            }
        }
    }
}())

Использование:

signup.key.addEventListener('keyup', function() {
    delay(this).enqueue(300, function() {
        console.log(this.value)
    })
})

Код написан в стиле, который мне нравится, вам может понадобиться добавить несколько точек с запятой.

Что нужно иметь в виду:

  • Уникальный идентификатор генерируется на основе идентификатора формы и имени входа, поэтому они должны быть определены и уникальны, иначе вы можете настроить его в соответствии с вашей ситуацией.
  • задержка возвращает объект, который легко расширить для собственных нужд.
  • Исходный элемент, используемый для задержки, привязан к обратному вызову, поэтому this работает как положено (как в примере).
  • Пустое значение игнорируется во второй проверке.
  • Остерегайтесь enqueue , сначала он ожидает миллисекунды, я предпочитаю это, но вы можете переключить параметры так, чтобы они соответствовали setTimeout.

Решение, которое я использую, добавляет еще один уровень сложности, позволяя, например, отменить выполнение, но это хорошая база для построения.

2 голосов
/ 29 января 2016

Сочетание ответа CMS с ответом Мигеля дает надежное решение, допускающее одновременные задержки.

var delay = (function(){
    var timers = {};
    return function (callback, ms, label) {
        label = label || 'defaultTimer';
        clearTimeout(timers[label] || 0);
        timers[label] = setTimeout(callback, ms);
    };
})();

Когда вам нужно независимо отложить различные действия, используйте третий аргумент.

$('input.group1').keyup(function() {
    delay(function(){
        alert('Time elapsed!');
    }, 1000, 'firstAction');
});

$('input.group2').keyup(function() {
    delay(function(){
        alert('Time elapsed!');
    }, 1000, '2ndAction');
});
1 голос
/ 04 марта 2012

Используйте плагин bindWithDelay jQuery:

element.bindWithDelay(eventType, [ eventData ], handler(eventObject), timeout, throttle)
1 голос
/ 10 декабря 2013

Вот предложение, которое я написал, которое учитывает многократный ввод в вашу форму.

Эта функция получает объект поля ввода, введенный в ваш код

function fieldKeyup(obj){
    //  what you want this to do

} // fieldKeyup

Это фактическая функция delayCall, которая заботится о нескольких полях ввода

function delayCall(obj,ms,fn){
    return $(obj).each(function(){
    if ( typeof this.timer == 'undefined' ) {
       // Define an array to keep track of all fields needed delays
       // This is in order to make this a multiple delay handling     
          function
        this.timer = new Array();
    }
    var obj = this;
    if (this.timer[obj.id]){
        clearTimeout(this.timer[obj.id]);
        delete(this.timer[obj.id]);
    }

    this.timer[obj.id] = setTimeout(function(){
        fn(obj);}, ms);
    });
}; // delayCall

Использование:

$("#username").on("keyup",function(){
    delayCall($(this),500,fieldKeyup);
});
1 голос
/ 15 октября 2013
var globalTimeout = null;  
$('#search').keyup(function(){
  if(globalTimeout != null) clearTimeout(globalTimeout);  
  globalTimeout =setTimeout(SearchFunc,200);  
});
function SearchFunc(){  
  globalTimeout = null;  
  console.log('Search: '+$('#search').val());
  //ajax code
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...