如何触发延迟到用户暂停打字的 onkeyup 事件?

IT技术 javascript jquery ajax
2021-03-16 08:28:09

我有一个文本区域,人们在其中输入一些文本(自然地),并且我想让它不时发出 AJAX 请求,以获取有关文本区域内容的一些建议(如堆栈溢出的相关问题,但对于textarea,而不是文本输入)。问题是我不能在每次按键时都执行 AJAX 请求(这将是无用的并且非常消耗资源),而且我不确定最有效的方法是什么(每 X 字?每 X 秒) ? 或者是其他东西?)。

这样做的最佳方法是什么?

先感谢您。

6个回答

您可以将keypress事件处理程序与事件处理程序结合使用setTimeout以便您在按键后的设定时间发送 Ajax 请求,如果在计时器完成之前发生另一次按键,则取消并重新启动计时器。假设您有一个 ID 为“myTextArea”的 textarea 和一个名为 的 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 );
@barkmadley:如果您不想阻止其默认操作,那也没关系。您可以在按键处理程序中可靠地捕获退格键事件并阻止默认操作。
2021-04-20 08:28:09
@Tim Down:代码运行良好,但有一个问题:如果在 textarea 具有焦点时将 Alt-Tab(在 Windows 中)切换到另一个应用程序,然后再次返回 Alt-Tab,则会触发回调函数。它不应该,因为没有按下任何键。我不知道如何解决这个问题。
2021-04-24 08:28:09
如果您希望能够捕获退格键事件,请使用 onkeyup。
2021-04-28 08:28:09
谢谢蒂姆,出色的解决方案:D
2021-05-04 08:28:09
这是普遍接受的“正确”方式来做到这一点。说得好。
2021-05-14 08:28:09

您要查找的内容称为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>

这应该是我公认的解决方案......简单,干净,它可以让你在你想要的每个事件监听器上使用它......
2021-04-18 08:28:09

另一种选择是使用一个名为bindWithDelay的小型 jQuery 插件它使用与接受的答案相同的 setTimeout 技术,但透明地处理超时,因此您的代码更容易阅读。源代码可以看出在github。

$("#myTextArea").bindWithDelay("keypress", doAjaxStuff, 1000)

如果您使用 lodash.js(或 underscore.js),您可以使用 debounce函数

示例(用于 keyup 的 jQuery):

$('#myTextArea').keyup(_.debounce(function() {
  alert('hello');
}, 500));

如果您对 jQuery 解决方案感兴趣,jQuery Suggest是一个很好的实现。

每次都重新发明轮子是没有意义的。

这对我不起作用,因为我不想用提出的建议更新 textarea 或任何内容。我只是想发出一个 AJAX 请求来获取页面中另一个元素的内容,每次 X 键击,或者用户输入的每 X 秒,等等。只是想知道什么是最有效的选择。
2021-04-27 08:28:09