Как вызвать событие onkeyup, которое задерживается до тех пор, пока пользователь не приостановит набор текста? - PullRequest
33 голосов
/ 25 октября 2009

У меня есть текстовая область, куда люди вводят некоторый текст (естественно), и я хочу сделать так, чтобы время от времени делался запрос AJAX, чтобы получить некоторые предложения относительно того, что такое текстовая область (например, связанные вопросы переполнения стека, но для текстовой области, а не для ввода текста). Проблема в том, что я не могу выполнить AJAX-запрос при каждом нажатии клавиши (это было бы бесполезно и потребляло много ресурсов), и я не уверен, что было бы наиболее эффективным способом сделать это (каждые X слов? Каждые X секунд ? или что-то еще?).

Каков наилучший способ сделать это?

Заранее спасибо.

Ответы [ 7 ]

64 голосов
/ 25 октября 2009

Вы можете объединить обработчик событий keypress с setTimeout, чтобы отправлять запрос Ajax через заданное количество времени после нажатия клавиши, отменяя и перезапуская таймер, если другое нажатие клавиши происходит до его окончания. Предполагая, что у вас есть текстовая область с идентификатором «myTextArea» и функция обратного вызова Ajax с именем doAjaxStuff:

function addTextAreaCallback(textArea, callback, delay) {
    var timer = null;
    textArea.onkeypress = function() {
        if (timer) {
            window.clearTimeout(timer);
        }
        timer = window.setTimeout( function() {
            timer = null;
            callback();
        }, delay );
    };
    textArea = null;
}

addTextAreaCallback( document.getElementById("myTextArea"), doAjaxStuff, 1000 );
12 голосов
/ 27 января 2016

То, что вы ищете, называется debouncing. Вот общий алгоритм в нативном JavaScript:

function debounce(fn, duration) {
  var timer;
  return function() {
    clearTimeout(timer);
    timer = setTimeout(fn, duration)
  }
}

А вот пример того, как использовать его с событием onkeyup:

function debounce(fn, duration) {
  var timer;
  return function(){
    clearTimeout(timer);
    timer = setTimeout(fn, duration);
  }
}

const txt = document.querySelector('#txt')
const out = document.querySelector('#out')
const status = document.querySelector('#status')

const onReady = () => {
  txt.addEventListener('keydown', () => {
    out.classList.remove('idle')
    out.classList.add('typing')
    status.textContent = 'typing...'
  })
  
  txt.addEventListener('keyup', debounce(() => {
    out.classList.remove('typing')
    out.classList.add('idle')
    status.textContent = 'idle...'
  }, 800))
}

document.addEventListener('DOMContentLoaded', onReady)
#wrapper{
  width: 300px;
}

input{
  padding: 8px;
  font-size: 16px;
  width: 100%;
  box-sizing: border-box;
}

#out{
  margin: 10px 0;
  padding: 8px;
  width: 100%;
  box-sizing: border-box;
}

.typing{
  background: #A00;
  color: #FFF;
}

.idle{
  background: #0A0;
  color: #FFF;
}
<div id="wrapper">
  <input id="txt" placeholder="Type here" />
  <div id="out">Status: <span id="status">waiting...</span></div>
</div>
9 голосов
/ 13 августа 2010

Другая альтернатива - использовать небольшой плагин jQuery с именем bindWithDelay . Он использует ту же технику setTimeout, что и принятый ответ, но прозрачно обрабатывает таймауты, поэтому ваш код немного легче читать. Исходный код можно увидеть на github.

$("#myTextArea").bindWithDelay("keypress", doAjaxStuff, 1000)
3 голосов
/ 29 октября 2013

Если вы используете lodash.js (или underscore.js), вы можете использовать функцию debounce .

Пример (jQuery используется для keyup):

$('#myTextArea').keyup(_.debounce(function() {
  alert('hello');
}, 500));
1 голос
/ 25 октября 2009

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

0 голосов
/ 11 декабря 2010

Если вы используете эту функцию по всему сайту и не хотите отслеживать все ссылки на setTimeout и т. Д., То я упаковал это в плагин, доступный здесь .

Плагин добавляет несколько опций к обычному методу $ .ajax для буферизации и отмены предыдущих вызовов ajax.

0 голосов
/ 25 октября 2009

Если вас интересуют решения jQuery, jQuery Suggest - хорошая реализация.

Нет смысла изобретать велосипед каждый раз.

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