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

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

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

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

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

Ответы [ 25 ]

1032 голосов
/ 15 декабря 2009

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

Как это работает:

Функция delay вернет упакованную функцию, которая внутренне обрабатывает отдельный таймер, при каждом выполнении таймер перезапускается с предоставленной задержкой, если несколько выполнений выполняются до того, как пройдет это время, таймер просто сбрасывается и запускается снова. .

Когда таймер наконец-то заканчивается, выполняется функция обратного вызова, передавая исходный контекст и аргументы (в этом примере объект события jQuery и элемент DOM как this).

ОБНОВЛЕНИЕ 2019-05-16

Я заново реализовал функцию с использованием функций ES5 и ES6 для современных сред:

function delay(fn, ms) {
  let timer = 0
  return function(...args) {
    clearTimeout(timer)
    timer = setTimeout(fn.bind(this, ...args), ms || 0)
  }
}

Реализация покрыта набором тестов .

Для чего-то более сложного, взгляните на плагин jQuery Typewatch .

57 голосов
/ 15 декабря 2009

Если вы хотите выполнить поиск после завершения типа, используйте глобальную переменную, чтобы сохранить время ожидания, возвращаемое вашим вызовом 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);  
}   
30 голосов
/ 09 октября 2013

Еще одно небольшое улучшение в ответе 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);});
28 голосов
/ 18 февраля 2011

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

var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);
14 голосов
/ 13 марта 2012

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

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

/*
 * delayKeyup
 * http://code.azerti.net/javascript/jquery/delaykeyup.htm
 * Inspired by CMS in this post : /920805/kak-otlozhit-obrabotchik-keyup-poka-polzovatel-ne-perestanet-pechatat
 * 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) в функции, переданная в качестве параметра, не соответствует вводу

11 голосов
/ 28 мая 2015

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

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

Таким образом, в результате будет вызван только последний щелчок / действие, поскольку эти запросы хранятся в очереди, то есть после вызова 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);});

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

6 голосов
/ 25 сентября 2012

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

$.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/

6 голосов
/ 07 января 2016

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

function MyFunction() {

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

        //Execute the function code here...

    }, 500);
}
6 голосов
/ 28 мая 2016

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

<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>
6 голосов
/ 01 сентября 2013

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

$('#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);
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...