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

我有一个文本区域,人们(自然地)在其中输入一些文本,我想这样做,以便不时发出 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】:

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

【讨论】:

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

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

示例(用于 keyup 的 jQuery):

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        您可以将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,回调函数被解雇。它不应该,因为没有按下任何键。我不知道如何解决这个问题。
        【解决方案6】:

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

        【讨论】:

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

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

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

        【讨论】:

        • 这对我不起作用,因为我不想用所提出的建议来更新 textarea 或任何内容。我只想发出一个 AJAX 请求,以获取页面中另一个元素的内容、每 X 次击键或用户输入的每 X 秒,或其他内容。只是想知道什么是最有效的选择。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多