Запустить функцию javascript, когда пользователь закончит ввод, а не при нажатии клавиши? - PullRequest
414 голосов
/ 19 ноября 2010

Я хочу вызвать ajax-запрос, когда пользователь закончит вводить текстовое поле. Я не хочу, чтобы он запускал эту функцию каждый раз, когда пользователь вводит букву, потому что это приведет к МНОЖЕСТВУ ajax-запросов, однако я не хочу, чтобы они также нажимали кнопку ввода.

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

Используя jQuery здесь! Dave

Ответы [ 24 ]

600 голосов
/ 19 ноября 2010

Итак, я предполагаю, что завершение набора означает, что вы просто остановитесь на некоторое время, скажем, 5 секунд.Итак, помня об этом, давайте запустим таймер, когда пользователь отпускает клавишу, и сбросим его, когда нажмем одну.Я решил, что рассматриваемый ввод будет # myInput.

Делая несколько предположений ...

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms, 5 second for example
var $input = $('#myInput');

//on keyup, start the countdown
$input.on('keyup', function () {
  clearTimeout(typingTimer);
  typingTimer = setTimeout(doneTyping, doneTypingInterval);
});

//on keydown, clear the countdown 
$input.on('keydown', function () {
  clearTimeout(typingTimer);
});

//user is "finished typing," do something
function doneTyping () {
  //do something
}
351 голосов
/ 08 мая 2011

Выбранный ответ выше не работает.

Поскольку typingTimer иногда устанавливается несколько раз (нажатие клавиши дважды до нажатия клавиши для быстрого набора текста и т. Д.), Тогда оно не очищается должным образом.

Решение, приведенное ниже, решает эту проблему и вызывает X секунд после завершения, как было запрошено OP. Также больше не требуется избыточная функция нажатия клавиш. Я также добавил проверку, чтобы ваш вызов функции не происходил, если ваш ввод пуст.

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms (5 seconds)

//on keyup, start the countdown
$('#myInput').keyup(function(){
    clearTimeout(typingTimer);
    if ($('#myInput').val()) {
        typingTimer = setTimeout(doneTyping, doneTypingInterval);
    }
});

//user is "finished typing," do something
function doneTyping () {
    //do something
}

И тот же код в ванильном решении JavaScript:

//setup before functions
let typingTimer;                //timer identifier
let doneTypingInterval = 5000;  //time in ms (5 seconds)
let myInput = document.getElementById('myInput');

//on keyup, start the countdown
myInput.addEventListener('keyup', () => {
    clearTimeout(typingTimer);
    if (myInput.value) {
        typingTimer = setTimeout(doneTyping, doneTypingInterval);
    }
});

//user is "finished typing," do something
function doneTyping () {
    //do something
}

В этом решении используется ES6, но здесь нет необходимости. Просто замените let на var, а функцию стрелки на обычную функцию.

69 голосов
/ 01 мая 2013

Это просто одна строка с underscore.js функция debounce:

$('#my-input-box').keyup(_.debounce(doSomething , 500));

Это в основном говорит doSomething 500 миллисекунд после того, как я перестал печатать.

Для получения дополнительной информации: http://underscorejs.org/#debounce

40 голосов
/ 19 ноября 2010

Да, вы можете установить тайм-аут, скажем, 2 секунды на каждое событие key up, которое вызовет запрос ajax.Вы также можете сохранить метод XHR и прервать его при последующих событиях нажатия клавиш, чтобы еще больше сохранить полосу пропускания.Вот что я написал для моего сценария автозаполнения.

var timer;
var x;

$(".some-input").keyup(function () {
    if (x) { x.abort() } // If there is an existing XHR, abort it.
    clearTimeout(timer); // Clear the timer so we don't end up with dupes.
    timer = setTimeout(function() { // assign timer a new timeout 
        x = $.getJSON(...); // run ajax request and store in x variable (so we can cancel)
    }, 2000); // 2000ms delay, tweak for faster/slower
});

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

Marko

17 голосов
/ 14 августа 2012
var timer;
var timeout = 1000;

$('#in').keyup(function(){
    clearTimeout(timer);
    if ($('#in').val) {
        timer = setTimeout(function(){
            //do stuff here e.g ajax call etc....
             var v = $("#in").val();
             $("#out").html(v);
        }, timeout);
    }
});

полный пример здесь: http://jsfiddle.net/ZYXp4/8/

10 голосов
/ 15 января 2014

Мне нравится ответ Surreal Dream, но я обнаружил, что моя функция doneTyping будет срабатывать при каждом нажатии клавиши, т. Е. Если вы действительно быстро наберете "Hello";вместо того, чтобы запускаться один раз, когда вы прекращаете печатать, функция сработала бы 5 раз.

Проблема заключалась в том, что функция setTimeout javascript, по-видимому, не перезаписывала и не уничтожала любые старые установленные таймауты, но еслиВы делаете это сами, это работает!Поэтому я просто добавил вызов clearTimeout непосредственно перед setTimeout, если установлен typingTimer.См. Ниже:

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms, 5 second for example

//on keyup, start the countdown
$('#myInput').on("keyup", function(){
    if (typingTimer) clearTimeout(typingTimer);                 // Clear if already set     
    typingTimer = setTimeout(doneTyping, doneTypingInterval);
});

//on keydown, clear the countdown 
$('#myInput').on("keydown", function(){
    clearTimeout(typingTimer);
});

//user is "finished typing," do something
function doneTyping () {
    //do something
}

NB. Мне бы хотелось добавить это в качестве комментария к ответу Surreal Dream, но я новый пользователь и мне не хватает репутации.Извините!

8 голосов
/ 30 августа 2016

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

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 2000;  //time in ms, 2 second for example
var $input = $('#myInput');

// updated events 
$input.on('input propertychange paste', function () {
    clearTimeout(typingTimer);
    typingTimer = setTimeout(doneTyping, doneTypingInterval);      
});

//user is "finished typing," do something
function doneTyping () {
  //do something
}
6 голосов
/ 08 февраля 2018

Оба топ-2 ответа не работают для меня. Итак, вот мое решение:

var timeout = null;

$('#myInput').keyup(function() {
    clearTimeout(timeout);

    timeout = setTimeout(function() {
        //do stuff here
    }, 500);
});
4 голосов
/ 05 октября 2011

Я не думаю, что событие keyDown необходимо в этом случае (пожалуйста, скажите мне, почему, если я ошибаюсь).В моем (не jquery) сценарии похожее решение выглядит так:

var _timer, _timeOut = 2000; 



function _onKeyUp(e) {
    clearTimeout(_timer);
    if (e.keyCode == 13) {      // close on ENTER key
        _onCloseClick();
    } else {                    // send xhr requests
        _timer = window.setTimeout(function() {
            _onInputChange();
        }, _timeOut)
    }

}

Это мой первый ответ о переполнении стека, поэтому я надеюсь, что когда-нибудь это кому-нибудь поможет:)

4 голосов
/ 19 ноября 2010

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

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

(Если, конечно, вы не можете узнать по данным, когда они сделаны)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...