Как задержать обработчик .keyup(), пока пользователь не перестанет печатать?

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

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

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

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

Ответ 1

Я использую эту маленькую функцию для той же цели, выполняя функцию после того, как пользователь прекратил печатать в течение определенного периода времени или в событиях, которые запускаются с высокой скоростью, таких как resize:

function delay(callback, ms) {
  var timer = 0;
  return function() {
    var context = this, args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function () {
      callback.apply(context, args);
    }, ms || 0);
  };
}


// Example usage:

$('#input').keyup(delay(function (e) {
  console.log('Time elapsed!', this.value);
}, 500));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label for="input">Try it:
<input id="input" type="text" placeholder="Type something here..."/>
</label>

Ответ 2

Если вы хотите выполнить поиск после завершения типа, используйте глобальную переменную, чтобы удерживать тайм-аут, возвращенный с вашего вызова setTimout, и отмените его с помощью clearTimeout, если он еще не появился, чтобы он не срабатывал таймаут, кроме последнего события keyup

var globalTimeout = null;  
$('#id').keyup(function(){
  if(globalTimeout != null) clearTimeout(globalTimeout);  
  globalTimeout =setTimeout(SearchFunc,200);  
}   
function SearchFunc(){  
  globalTimeout = null;  
  //ajax code
}

Или с анонимной функцией:

var globalTimeout = null;  
$('#id').keyup(function() {
  if (globalTimeout != null) {
    clearTimeout(globalTimeout);
  }
  globalTimeout = setTimeout(function() {
    globalTimeout = null;  

    //ajax code

  }, 200);  
}   

Ответ 3

Еще одно небольшое улучшение в ответе CMS. Чтобы легко разрешить отдельные задержки, вы можете использовать следующее:

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

Если вы хотите повторно использовать ту же задержку, просто сделайте

var delay = makeDelay(250);
$(selector1).on('keyup', function() {delay(someCallback);});
$(selector2).on('keyup', function() {delay(someCallback);});

Если вам нужны отдельные задержки, вы можете сделать

$(selector1).on('keyup', function() {makeDelay(250)(someCallback);});
$(selector2).on('keyup', function() {makeDelay(250)(someCallback);});

Ответ 4

Вы также можете посмотреть underscore.js, который предоставляет полезные методы, такие как debounce:

var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);

Ответ 5

Основываясь на ответе CMS, я сделал следующее:

Поместите код ниже после включения jQuery:

/*
 * delayKeyup
 * http://code.azerti.net/javascript/jquery/delaykeyup.htm
 * Inspired by CMS in this post : http://stackoverflow.com/questions/1909441/jquery-keyup-delay
 * Written by Gaten
 * Exemple : $("#input").delayKeyup(function(){ alert("5 secondes passed from the last event keyup."); }, 5000);
 */
(function ($) {
    $.fn.delayKeyup = function(callback, ms){
        var timer = 0;
        $(this).keyup(function(){                   
            clearTimeout (timer);
            timer = setTimeout(callback, ms);
        });
        return $(this);
    };
})(jQuery);

И просто используйте вот так:

$('#input').delayKeyup(function(){ alert("5 secondes passed from the last event keyup."); }, 5000);

Осторожно: переменная $(this) в функции, переданной как параметр, не соответствует вводу

Ответ 6

Задержка многофункциональных вызовов с использованием меток

Это решение, с которым я работаю. Это задержит выполнение ЛЮБОЙ функции, которую вы хотите. Это может быть поисковый запрос по нажатию клавиши, может быть быстрый щелчок по предыдущей или следующей кнопке (в противном случае отправка множественного запроса будет выполняться при быстром щелчке и не будет использоваться в конце концов). При этом используется глобальный объект, который сохраняет каждое время выполнения и сравнивает его с самым последним запросом.

Таким образом, в результате будет вызван только последний щелчок/действие, поскольку эти запросы хранятся в очереди, то есть после вызова X миллисекунд, если в очереди не существует другого запроса с такой же меткой!

function delay_method(label,callback,time){
    if(typeof window.delayed_methods=="undefined"){window.delayed_methods={};}  
    delayed_methods[label]=Date.now();
    var t=delayed_methods[label];
    setTimeout(function(){ if(delayed_methods[label]!=t){return;}else{  delayed_methods[label]=""; callback();}}, time||500);
  }

Вы можете установить собственное время задержки (необязательно, по умолчанию 500 мс). И отправьте аргументы вашей функции в "режиме закрытия".

Например, если вы хотите вызвать нижеуказанную функцию:

function send_ajax(id){console.log(id);}

Чтобы предотвратить несколько запросов send_ajax, вы задерживаете их, используя:

delay_method( "check date", function(){ send_ajax(2); } ,600);

Каждый запрос, использующий метку "дата проверки", будет запускаться только в том случае, если в течение 600 миллисекунд не было сделано ни одного другого запроса. Этот аргумент не является обязательным

Пометьте независимость (вызывая ту же целевую функцию), но запустите оба:

delay_method("check date parallel", function(){send_ajax(2);});
delay_method("check date", function(){send_ajax(2);});

Приводит к вызову одной и той же функции, но задерживает их независимо, потому что их метки отличаются

Ответ 7

Эта функция немного расширяет функцию ответа Gaten, чтобы вернуть элемент:

$.fn.delayKeyup = function(callback, ms){
    var timer = 0;
    var el = $(this);
    $(this).keyup(function(){                   
    clearTimeout (timer);
    timer = setTimeout(function(){
        callback(el)
        }, ms);
    });
    return $(this);
};

$('#input').delayKeyup(function(el){
    //alert(el.val());
    // Here I need the input element (value for ajax call) for further process
},1000);

http://jsfiddle.net/Us9bu/2/

Ответ 8

Это сработало для меня, когда я задерживаю операцию поиска и делаю проверку, если значение такое же, как указано в текстовом поле. Если значение такое же, тогда я иду вперед и выполняю операцию для данных, относящихся к значению поиска.

$('#searchText').on('keyup',function () {
    var searchValue = $(this).val();
    setTimeout(function(){
        if(searchValue == $('#searchText').val() && searchValue != null && searchValue != "") {
           // logic to fetch data based on searchValue
        }
        else if(searchValue == ''){
           // logic to load all the data
        }
    },300);
});

Ответ 9

Я удивлен, что никто не упоминает проблему с несколькими входами в CMS очень красиво отрезанным.

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

См. код ниже. Я пришел с учетом других ответов:

(function($) {
    /**
     * KeyUp with delay event setup
     * 
     * @link http://stackoverflow.com/questions/1909441/jquery-keyup-delay#answer-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 в переменной ввода delayTimer. Он также передает ссылку элемента на обратный вызов, как предположил fazzyx.

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

Ответ 10

Если кому-то нравится откладывать одну и ту же функцию и без внешней переменной, он может использовать следующий script:

function MyFunction() {

    //Delaying the function execute
    if (this.timer) {
        window.clearTimeout(this.timer);
    }
    this.timer = window.setTimeout(function() {

        //Execute the function code here...

    }, 500);
}

Ответ 11

Супер простой подход, предназначенный для запуска функции после того, как пользователь закончил печатать в текстовом поле...

<script type="text/javascript">
$(document).ready(function(e) {
    var timeout;
    var delay = 2000;   // 2 seconds

    $('.text-input').keyup(function(e) {
        console.log("User started typing!");
        if(timeout) {
            clearTimeout(timeout);
        }
        timeout = setTimeout(function() {
            myFunction();
        }, delay);
    });

    function myFunction() {
        console.log("Executing function for user!");
    }
});
</script>

<textarea name="text-input" class="text-input"></textarea>

Ответ 12

Функция задержки для вызова каждой клавиши. 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 );

Ответ 13

Основываясь на 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);
});

Ответ 14

Используйте

mytimeout = setTimeout( expression, timeout );

где выражение - это script для запуска, а время ожидания - это время ожидания в миллисекундах перед его запуском - это НЕ ХАРАКТЕРИСТИРОВАТЬ script, а просто задерживает выполнение этой части до истечения таймаута.

clearTimeout(mytimeout);

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

Ответ 15

Это решение по линии 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)
    })
})

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

Что нужно помнить:

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

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

Ответ 16

Основываясь на ответе 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 );


})

Ответ 17

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

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

Ответ 18

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

element.bindWithDelay(eventType, [ eventData ], handler(eventObject), timeout, throttle)

Ответ 19

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

Ответ 20

Вот предложение, которое я написал, который заботится о нескольких вводах в вашей форме.

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

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

Ответ 21

Взгляните на плагин autocomplete. Я знаю, что он позволяет указать задержку или минимальное количество символов. Даже если вы не используете плагин, просмотр кода даст вам некоторые идеи о том, как его реализовать самостоятельно.

Ответ 22

Ну, я также сделал фрагмент кода для ограничения высокочастотного запроса ajax-запроса Keyup/Keydown. Проверьте это:

https://github.com/raincious/jQueue

Сделайте свой запрос следующим образом:

var q = new jQueue(function(type, name, callback) {
    return $.post("/api/account/user_existed/", {Method: type, Value: name}).done(callback);
}, 'Flush', 1500); // Make sure use Flush mode.

И привяжите событие следующим образом:

$('#field-username').keyup(function() {
    q.run('Username', this.val(), function() { /* calling back */ });
});

Ответ 23

Видел это сегодня немного поздно, но просто хочу поставить это здесь, если кому-то еще понадобится. просто отделите функцию, чтобы сделать ее многоразовой. код ниже будет ждать полтора секунды после остановки печати. ​​

    var timeOutVar
$(selector).on('keyup', function() {

                    clearTimeout(timeOutVar);
                    timeOutVar= setTimeout(function(){ console.log("Hello"); }, 500);
                });

Ответ 24

С ES6 можно также использовать синтаксис функции стрелки.

В этом примере код задерживает keyup события для 400мса после того как пользователь закончить typeing перед вызовом searchFunc сделать запрос на запрос.

const searchbar = document.getElementById('searchBar');
const searchFunc = // any function

// wait ms (milliseconds) after user stops typing to execute func
const delayKeyUp = (() => {
    let timer = null;
    const delay = (func, ms) => {
        timer ? clearTimeout(timer): null
        timer = setTimeout(func, ms)
    }
    return delay
})();

searchbar.addEventListener('keyup', (e) => {
    const query = e.target.value;
    delayKeyUp(() => {searchFunc(query)}, 400);
})

Ответ 25

Пользовательская библиотека lodash javascript и использование функции _.debounce

changeName: _.debounce(function (val) {
  console.log(val)                
}, 1000)