Как вызвать событие во входном тексте после того, как я перестал печатать / писать?

85

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

Я пробовал:

$('input#username').keypress(function() {
    var _this = $(this); // copy of this object for further usage

    setTimeout(function() {
        $.post('/ajax/fetch', {
            type: 'username',
            value: _this.val()
        }, function(data) {
            if(!data.success) {
                // continue working
            } else {
                // throw an error
            }
        }, 'json');
    }, 3000);
});

Но в этом примере создается тайм-аут для каждого набранного символа, и я получаю около 20 запросов AJAX, если набираю 20 символов.

На этой скрипке я демонстрирую ту же проблему с простым предупреждением вместо AJAX.

Есть ли решение для этого или я просто использую для этого плохой подход?

Fuhrmanator
источник
1
Я боюсь, что javascript не предоставляет событие, которое позволило бы вам получать уведомления, когда пользователь прекращает вводить текст в поле ввода. Зачем тебе это надо?
Дарин Димитров
3
разве это не очевидно из примера? Я хочу вызвать событие «когда конечный пользователь перестанет вводить его» вместо отправки 20 запросов
1
Невозможно определить, когда пользователь действительно закончил ввод, если он вручную не отправит или не изменит поля. Как узнать, делает ли пользователь паузу в середине предложения и ждет 5 минут, прежде чем набрать еще? Возможное решение - использовать .blur () и отправлять, когда фокус пользователя покидает поле.
Kevin M
14
Комментарии выше глупые. Это распространенный вариант использования: мне нужно одно событие, когда пользователь завершает изменение размера своего окна, масштабирование карты, перетаскивание, ввод текста ... в основном любое непрерывное действие со стороны пользователя должно быть переведено в нашу цифровую вселенную. Даже одно нажатие клавиши страдает от этой проблемы: когда вы нажимаете клавишу, она фактически "подпрыгивает", создавая не только одно нажатие клавиши, но и множество. Аппаратное обеспечение или ОС вашего компьютера удаляют эти лишние события, и поэтому у нас есть иллюзия дискретных событий нажатия клавиш. Это называется «противодействие», и это то, что нужно OP.
Ziggy
предупреждение для реагирующих пользователей: stackoverflow.com/a/28046731/57883
Маслоу

Ответы:

172

Вам нужно будет использовать setTimeout(как и вы), но также сохранить ссылку, чтобы вы могли продолжать сбрасывать лимит. Что-то вроде:

//
// $('#element').donetyping(callback[, timeout=1000])
// Fires callback when a user has finished typing. This is determined by the time elapsed
// since the last keystroke and timeout parameter or the blur event--whichever comes first.
//   @callback: function to be called when even triggers
//   @timeout:  (default=1000) timeout, in ms, to to wait before triggering event if not
//              caused by blur.
// Requires jQuery 1.7+
//
;(function($){
    $.fn.extend({
        donetyping: function(callback,timeout){
            timeout = timeout || 1e3; // 1 second default timeout
            var timeoutReference,
                doneTyping = function(el){
                    if (!timeoutReference) return;
                    timeoutReference = null;
                    callback.call(el);
                };
            return this.each(function(i,el){
                var $el = $(el);
                // Chrome Fix (Use keyup over keypress to detect backspace)
                // thank you @palerdot
                $el.is(':input') && $el.on('keyup keypress paste',function(e){
                    // This catches the backspace button in chrome, but also prevents
                    // the event from triggering too preemptively. Without this line,
                    // using tab/shift+tab will make the focused element fire the callback.
                    if (e.type=='keyup' && e.keyCode!=8) return;
                    
                    // Check if timeout has been set. If it has, "reset" the clock and
                    // start over again.
                    if (timeoutReference) clearTimeout(timeoutReference);
                    timeoutReference = setTimeout(function(){
                        // if we made it here, our timeout has elapsed. Fire the
                        // callback
                        doneTyping(el);
                    }, timeout);
                }).on('blur',function(){
                    // If we can, fire the event since we're leaving the field
                    doneTyping(el);
                });
            });
        }
    });
})(jQuery);

$('#example').donetyping(function(){
  $('#example-output').text('Event last fired @ ' + (new Date().toUTCString()));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<input type="text" id="example" />
<p id="example-output">Nothing yet</p>

Это будет выполнено, когда:

  1. Истекло время ожидания или
  2. Пользователь переключил поля ( blurсобытие)

(Что наступит раньше)

Брэд Кристи
источник
1
Да, это спасает мне ночь. Спасибо
новичок
2
@Brad: это решение jquery работает нормально, за исключением того, что клавиша Backspace, введенная в поле ввода, не обнаруживается в последней версии Chrome (38.0.2125.111). Только меняю на keyupработает. Вы можете проверить это и соответствующим образом изменить код.
palerdot
1
@palerdot: Приятно знать, спасибо. Я изучу его и опубликую все изменения.
Брэд Кристи
3
Спасибо за этот плагин - отлично работает. Мне пришлось внести одну корректировку, потому что это не сработает, если кто-то вставит что-то в поле ввода. Я отредактировал следующую строку, чтобы включить paste -$el.is(':input') && $el.on('keyup keypress paste',function(e){
Мэтт
1
@ Sangar82: Должен теперь (хотя я немного сбит с толку, ctrl + v должен быть захвачен нажатием клавиши - если только вы не щелкнете правой кнопкой мыши-> вставка?
Брэд Кристи,
71

РЕШЕНИЕ:

Вот решение. Выполнение функции после того, как пользователь перестал печатать в течение определенного времени:

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

Применение

$('input').keyup(function() {
  delay(function(){
    alert('Hi, func called');
  }, 1000 );
});
Ата-уль-Мустафа
источник
1
user1386320 - Проверьте это решение. У меня аналогичная проблема, и она работает. Вы добавите свой код вместо alert ().
Ата ул Мустафа
Благодарю. Прекрасно работает.
user1919
2
Могу я добавить N + Up голосов? Это блестящее, короткое и элегантное решение с использованием замыканий JavaScript.
Маттео Конта,
1
@MatteoConta, Спасибо :)
Ата ул Мустафа
1
Я не хотел включать файл underscore.js на свою страницу только для этого. Ваше решение работает отлично! Спасибо
Skoempie
17

Вы можете использовать underscore.js «debounce»

$('input#username').keypress( _.debounce( function(){<your ajax call here>}, 500 ) );

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

Для дополнительной информации использование _.debounce (func, timer, true ) будет означать, что первая функция будет выполняться, а все другие события нажатия клавиш с последующими таймерами 500 мс будут проигнорированы.

СкорпионКинг2k5
источник
Очень полезно и коротко, если вы уже подчеркнули как lib.
Francesco Pasa,
10

Вам нужен дребезг!

Вот плагин jQuery , и вот все, что вам нужно знать о debounce . Если вы едете сюда из Google и подчерка нашел свой путь в JSoup вашего приложения, он имеет дребезг выпекаться !

Зигги
источник
6

очищенный раствор:

$.fn.donetyping = function(callback, delay){
  delay || (delay = 1000);
  var timeoutReference;
  var doneTyping = function(elt){
    if (!timeoutReference) return;
    timeoutReference = null;
    callback(elt);
  };

  this.each(function(){
    var self = $(this);
    self.on('keyup',function(){
      if(timeoutReference) clearTimeout(timeoutReference);
      timeoutReference = setTimeout(function(){
        doneTyping(self);
      }, delay);
    }).on('blur',function(){
      doneTyping(self);
    });
  });

  return this;
};
Матрица
источник
6

Вы должны присвоить setTimeoutпеременной и использовать ее clearTimeoutдля очистки при нажатии клавиши.

var timer = '';

$('input#username').keypress(function() {
  clearTimeout(timer);
  timer = setTimeout(function() {
    //Your code here
  }, 3000); //Waits for 3 seconds after last keypress to execute the above lines of code
});

Скрипка

Надеюсь это поможет.

Гибин Иалиас
источник
3

Я сделал простой плагин , который делает именно это. Требуется гораздо меньше кода, чем предлагаемые решения, и он очень легкий (~ 0,6 КБ)

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

var searchBid = new Bid(function(inputValue){
    //your action when user will stop writing for 200ms. 
    yourSpecialAction(inputValue);
}, 200); //we set delay time of every bump to 200ms

Когда Bidобъект готов, нам это нужно bumpкак-то. Прикрепим неровности к keyup event.

$("input").keyup(function(){
    searchBid.bump( $(this).val() ); //parameters passed to bump will be accessable in Bid callback
});

Здесь происходит следующее:

Каждый раз, когда пользователь нажимает клавишу, ставка «задерживается» (повышается) на следующие 200 мс. Если пройдет 200 мсек без повторного «толчка», обратный вызов будет запущен.

Кроме того, у вас есть 2 дополнительные функции для остановки ставки (например, если пользователь нажал esc или щелкнул вне ввода) и для немедленного завершения и запуска обратного вызова (например, когда пользователь нажимает клавишу ввода):

searchBid.stop();
searchBid.finish(valueToPass);
Адам Пьетрасиак
источник
1

Я искал простой код HTML / JS и не нашел. Затем я написал приведенный ниже код, используя onkeyup="DelayedSubmission()".

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pt-br" lang="pt-br">
<head><title>Submit after typing finished</title>
<script language="javascript" type="text/javascript">
function DelayedSubmission() {
    var date = new Date();
    initial_time = date.getTime();
    if (typeof setInverval_Variable == 'undefined') {
            setInverval_Variable = setInterval(DelayedSubmission_Check, 50);
    } 
}
function DelayedSubmission_Check() {
    var date = new Date();
    check_time = date.getTime();
    var limit_ms=check_time-initial_time;
    if (limit_ms > 800) { //Change value in milliseconds
        alert("insert your function"); //Insert your function
        clearInterval(setInverval_Variable);
        delete setInverval_Variable;
    }
}

</script>
</head>
<body>

<input type="search" onkeyup="DelayedSubmission()" id="field_id" style="WIDTH: 100px; HEIGHT: 25px;" />

</body>
</html>
Альфредо Лингоист мл.
источник
0

зачем так много делать, если вы просто хотите сбросить часы?

var clockResetIndex = 0 ;
// this is the input we are tracking
var tarGetInput = $('input#username');

tarGetInput.on( 'keyup keypress paste' , ()=>{
    // reset any privious clock:
    if (clockResetIndex !== 0) clearTimeout(clockResetIndex);

    // set a new clock ( timeout )
    clockResetIndex = setTimeout(() => {
        // your code goes here :
        console.log( new Date() , tarGetInput.val())
    }, 1000);
});

Если вы работаете над wordpress, вам нужно обернуть весь этот код внутри блока jQuery:

jQuery(document).ready(($) => {
    /**
     * @name 'navSearch' 
     * @version 1.0
     * Created on: 2018-08-28 17:59:31
     * GMT+0530 (India Standard Time)
     * @author : ...
     * @description ....
     */
        var clockResetIndex = 0 ;
        // this is the input we are tracking
        var tarGetInput = $('input#username');

        tarGetInput.on( 'keyup keypress paste' , ()=>{
            // reset any privious clock:
            if (clockResetIndex !== 0) clearTimeout(clockResetIndex);

            // set a new clock ( timeout )
            clockResetIndex = setTimeout(() => {
                // your code goes here :
                console.log( new Date() , tarGetInput.val())
            }, 1000);
        });
});
insCode
источник
если вы хотите расширить jquery и хотите использовать этот метод в нескольких элементах ввода, то утвержденный ответ - это тот ответ, который вы ищете.
insCode
0

Используйте атрибут onkeyup = "myFunction ()" в <input>вашем html.

ХесамДжафарян
источник
-1

На мой взгляд, пользователь перестает писать, когда не сосредотачивается на вводе. Для этого у вас есть функция под названием «размытие», которая делает такие вещи, как

Стефанц
источник
4
неправильно! Размытие - это событие, когда фокус теряется на определенном поле ввода. мне нужно определить, когда клавиатура не используется в этом поле, в котором я пытаюсь вызвать событие.