如何触发延迟到用户暂停输入的 onkeyup 事件?
Posted
技术标签:
【中文标题】如何触发延迟到用户暂停输入的 onkeyup 事件?【英文标题】:How to trigger an onkeyup event that's delayed until a user pauses their typing? 【发布时间】: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 年得到审查。谈论彻底的审核。 【参考方案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 秒,或其他内容。只是想知道什么是最有效的选择。以上是关于如何触发延迟到用户暂停输入的 onkeyup 事件?的主要内容,如果未能解决你的问题,请参考以下文章
OnKeyPress、onKeyDown、onKeyUp 事件在 Android 下的 Firefox/Chrome 中在键入字母时未触发