【问题标题】:How to trigger an onkeyup event that's delayed until a user pauses their typing?如何触发延迟到用户暂停输入的onkeyup事件?
【发布时间】:2009-10-25 10:47:21
【问题描述】:

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

最好的方法是什么?

提前谢谢你。

【问题讨论】:

  • jQuery .keyup() delay的可能重复
  • @kenorb 这个问题实际上是第一个,你引用的问题被认为是这个问题的重复,但管理员不想关闭这个问题,因为标题更好,它有大约 132931 次查看,即相当了不起。
  • 这个老了没关系,另一个有更多的投票和观点,见:Should I flag a question as duplicate if it has received better answers?。标题可以随时编辑为更好的标题。他们可以一直是merged
  • 很酷,我 2009 年的问题在 2016 年得到审查。谈论彻底的审核。

标签: javascript jquery ajax


【解决方案1】:

您可以将keypress 事件处理程序与setTimeout 结合使用,这样您就可以在按键后的一段时间内发送Ajax 请求,如果在计时器完成之前发生另一个按键,则取消并重新启动计时器。假设你有一个 id 为 'myTextArea' 的 textarea 和一个名为 doAjaxStuff 的 Ajax 回调函数:

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 );

【讨论】:

  • 这是公认的“正确”方法。说得好。
  • 感谢蒂姆,出色的解决方案:D
  • 如果您希望能够捕获退格键事件,请使用 onkeyup。
  • @barkmadley:如果您不想阻止其默认操作,那很好。您可以在按键处理程序中可靠地捕获退格键事件并防止默认操作。
  • @Tim Down:代码运行良好,但有一个问题:如果您在 textarea 具有焦点时将 Alt-Tab(在 Windows 中)切换到另一个应用程序,然后再次返回 Alt-Tab,回调函数被解雇。它不应该,因为没有按下任何键。我不知道如何解决这个问题。
【解决方案2】:

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

【讨论】:

  • 这应该是我接受的解决方案...简单,干净,它可以让你在你想要的每个事件监听器上使用它...
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

    如果您使用的是 lodash.js(或 underscore.js),您可以使用 debounce function

    示例(用于 keyup 的 jQuery):

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

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

      • 这对我不起作用,因为我不想用所提出的建议来更新 textarea 或任何东西。我只想发出一个 AJAX 请求,以获取页面中另一个元素的内容、每 X 次击键或用户输入的每 X 秒,或其他内容。只是想知道什么是最有效的选择。
      【解决方案6】:

      我个人会使用setInterval 来监视文本区域的更改,并且仅在检测到更改时执行 AJAX 回调。每一秒都应该足够快和足够慢。

      【讨论】:

      • 这需要 setInterval 永远运行。 Tim 的解决方案更加优雅,仅在有人实际与文本框交互时运行。
      • 永远运行,直到页面被卸载。此外,如果您想在用户输入时提供一些反馈,我的解决方案会更好,因为如果用户输入速度超过每秒一个键,它就有机会发送请求。我并不是说 Tim 的解决方案不优雅,但在某些情况下它不是解决方案,具体取决于应用程序。
      【解决方案7】:

      如果您在网站上大量使用此功能并且不想跟踪所有 setTimeout 引用等,那么我将其打包成一个可用的插件here

      该插件为普通的 $.ajax 方法添加了一些选项,用于缓冲和取消以前的 ajax 调用。

      【讨论】:

        猜你喜欢
        • 2010-12-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多