Run javascript function when user finishes typing instead of on key up?
我想在用户输入文本框时触发ajax请求。 我不希望它在每次用户键入字母时都运行该函数,因为这会导致大量的ajax请求,但是我不希望它们也必须按下回车按钮。
有没有办法可以检测用户何时完成输入然后执行ajax请求?
在这里使用jQuery!
戴夫
所以,我猜猜完成打字就意味着你停了一会儿,说5秒钟。因此,考虑到这一点,让我们在用户释放密钥时启动计时器,并在按下密钥时清除它。我决定有问题的输入是#myInput。
做一些假设......
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //setup before functions var typingTimer; //timer identifier var doneTypingInterval = 5000; //time in ms, 5 second for example var $input = $('#myInput'); //on keyup, start the countdown $input.on('keyup', function () { clearTimeout(typingTimer); typingTimer = setTimeout(doneTyping, doneTypingInterval); }); //on keydown, clear the countdown $input.on('keydown', function () { clearTimeout(typingTimer); }); //user is"finished typing," do something function doneTyping () { //do something } |
上面选择的答案不起作用。
因为打字定时器被多次设置(在快速打字机等触发keydown之前按两次键盘)然后它没有正确清除。
下面的解决方案解决了这个问题,并在OP请求完成后调用X秒。它也不再需要冗余的keydown功能。我还添加了一个检查,以便在输入为空时不会发生函数调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //setup before functions var typingTimer; //timer identifier var doneTypingInterval = 5000; //time in ms (5 seconds) //on keyup, start the countdown $('#myInput').keyup(function(){ clearTimeout(typingTimer); if ($('#myInput').val()) { typingTimer = setTimeout(doneTyping, doneTypingInterval); } }); //user is"finished typing," do something function doneTyping () { //do something } |
和vanilla JavaScript解决方案中的相同代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //setup before functions let typingTimer; //timer identifier let doneTypingInterval = 5000; //time in ms (5 seconds) let myInput = document.getElementById('myInput'); //on keyup, start the countdown myInput.addEventListener('keyup', () => { clearTimeout(typingTimer); if (myInput.value) { typingTimer = setTimeout(doneTyping, doneTypingInterval); } }); //user is"finished typing," do something function doneTyping () { //do something } |
这个解决方案确实使用ES6,但这里没有必要。只需用
它只有一行with underscore.js去抖功能:
1 | $('#my-input-box').keyup(_.debounce(doSomething , 500)); |
这基本上是在我停止打字后500毫秒的doSomething。
欲了解更多信息:http://underscorejs.org/#debounce
是的,您可以在每个启动事件上设置2秒的超时,这将触发ajax请求。您还可以存储XHR方法并在随后的按键事件中将其中止,以便您节省带宽甚至更多。这是我为自己的自动完成脚本编写的内容。
1 2 3 4 5 6 7 8 9 10 | var timer; var x; $(".some-input").keyup(function () { if (x) { x.abort() } // If there is an existing XHR, abort it. clearTimeout(timer); // Clear the timer so we don't end up with dupes. timer = setTimeout(function() { // assign timer a new timeout x = $.getJSON(...); // run ajax request and store in x variable (so we can cancel) }, 2000); // 2000ms delay, tweak for faster/slower }); |
希望这可以帮助,
马尔科
1 2 3 4 5 6 7 8 9 10 11 12 13 | var timer; var timeout = 1000; $('#in').keyup(function(){ clearTimeout(timer); if ($('#in').val) { timer = setTimeout(function(){ //do stuff here e.g ajax call etc.... var v = $("#in").val(); $("#out").html(v); }, timeout); } }); |
这里有完整的例子:http://jsfiddle.net/ZYXp4/8/
我喜欢Surreal Dream的答案,但我发现我的"doneTyping"功能会触发每个按键,即如果你真的很快输入"Hello";当你停止输入时,该功能只会发射一次,而不是只发射一次。
问题是javascript setTimeout函数似乎没有覆盖或杀死已设置的任何旧超时,但如果你自己这样做它就可以了!所以我只是在setTimeout之前添加了一个clearTimeout调用,如果设置了typingTimer。见下文:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | //setup before functions var typingTimer; //timer identifier var doneTypingInterval = 5000; //time in ms, 5 second for example //on keyup, start the countdown $('#myInput').on("keyup", function(){ if (typingTimer) clearTimeout(typingTimer); // Clear if already set typingTimer = setTimeout(doneTyping, doneTypingInterval); }); //on keydown, clear the countdown $('#myInput').on("keydown", function(){ clearTimeout(typingTimer); }); //user is"finished typing," do something function doneTyping () { //do something } |
注:我本来希望将此作为对Surreal Dream答案的评论添加,但我是新用户并且没有足够的声誉。抱歉!
修改已接受的答案以处理其他案例,例如粘贴:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //setup before functions var typingTimer; //timer identifier var doneTypingInterval = 2000; //time in ms, 2 second for example var $input = $('#myInput'); // updated events $input.on('input propertychange paste', function () { clearTimeout(typingTimer); typingTimer = setTimeout(doneTyping, doneTypingInterval); }); //user is"finished typing," do something function doneTyping () { //do something } |
前两个答案都不适合我。所以,这是我的解决方案:
1 2 3 4 5 6 7 8 9 | var timeout = null; $('#myInput').keyup(function() { clearTimeout(timeout); timeout = setTimeout(function() { //do stuff here }, 500); }); |
好吧,严格来说不行,因为计算机无法猜到用户何时完成打字。当然,您可以在按键上启动计时器,并在每个后续按键上重置它。如果计时器到期,则用户没有键入计时器持续时间 - 您可以称之为"已完成输入"。
如果您希望用户在键入时暂停,则无法知道他们何时完成。
(当然,除非您完成后可以从数据中得知)
在这种情况下我不认为keyDown事件是必要的(请告诉我为什么我错了)。在我的(非jquery)脚本中,类似的解决方案看起来像这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | var _timer, _timeOut = 2000; function _onKeyUp(e) { clearTimeout(_timer); if (e.keyCode == 13) { // close on ENTER key _onCloseClick(); } else { // send xhr requests _timer = window.setTimeout(function() { _onInputChange(); }, _timeOut) } } |
这是我对Stack Overflow的第一个回复,所以我希望有一天能帮助某人:)
声明以下
1 2 3 4 5 6 7 | var delay = (function () { var timer = 0; return function (callback, ms) { clearTimeout(timer); timer = setTimeout(callback, ms); }; })() |
然后使用它:
1 2 3 4 5 6 | let $filter = $('#item-filter'); $filter.on('keydown', function () { delay(function () { console.log('this will hit, once user has not typed for 1 second'); }, 1000); }); |
我觉得使用
1 2 3 4 5 6 7 8 9 10 11 | var typingTimer; var doneTypingInterval = 500; $("#myInput").on("input", function () { window.clearTimeout(typingTimer); typingTimer = window.setTimeout(doneTyping, doneTypingInterval); }); function doneTyping () { // code here } |
同意@going的答案。另一个对我有用的类似解决方案是下面的解决方案。唯一的区别是我使用.on("输入"......)而不是键盘。这仅捕获输入中的更改。其他键如Ctrl,Shift等将被忽略
1 2 3 4 5 6 7 8 9 10 11 | var typingTimer; //timer identifier var doneTypingInterval = 5000; //time in ms (5 seconds) //on input change, start the countdown $('#myInput').on("input", function() { clearTimeout(typingTimer); typingTimer = setTimeout(function(){ // doSomething... }, doneTypingInterval); }); |
我正在我的列表中实现搜索,并且需要它是基于ajax的。这意味着在每次关键更改时,都应更新并显示搜索结果。这导致发送到服务器的这么多ajax调用,这不是一件好事。
经过一些工作,我做了一个方法来在用户停止输入时ping服务器。
这个解决方案对我有用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | $(document).ready(function() { $('#yourtextfield').keyup(function() { s = $('#yourtextfield').val(); setTimeout(function() { if($('#yourtextfield').val() == s){ // Check the value searched is the latest one or not. This will help in making the ajax call work when client stops writing. $.ajax({ type:"POST", url:"yoururl", data: 'search=' + s, cache: false, beforeSend: function() { // loading image }, success: function(data) { // Your response will come here } }) } }, 1000); // 1 sec delay to check. }); // End of keyup function }); // End of document.ready |
您会注意到在执行此操作时无需使用任何计时器。
我只想出一个简单的代码来等待用户完成输入:
步骤1.将超时设置为null,然后在用户键入时清除当前超时。
步骤2.触发keyup事件之前触发清除超时到变量define。
步骤3.对上面声明的变量定义超时;
1 | <input type="text" id="input" placeholder="please type" style="padding-left:20px;"/> |
javascript代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | var textInput = document.getElementById('input'); var textdata = document.querySelector('.data'); // Init a timeout variable to be used below var timefired = null; // Listen for keystroke events // Init a timeout variable to be used below var timefired = null;// Listen for keystroke events textInput.onkeyup = function (event) { clearTimeout(timefired); timefired = setTimeout(function () { textdata.innerHTML = 'Input Value:'+ textInput.value; }, 600); }; |
您可以使用onblur事件来检测文本框何时失去焦点:
https://developer.mozilla.org/en/DOM/element.onblur
这与"停止输入"不同,如果您关心用户输入一堆东西然后坐在那里仍然关注文本框的情况。
为此,我建议将setTimeout绑定到onclick事件,并假设在没有击键的x时间后,用户已停止输入。
这是我写的一个简单的JS代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <!DOCTYPE html PUBLIC"-//W3C//DTD XHTML 1.0 Strict//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pt-br" lang="pt-br"> <head>Submit after typing finished <script language="javascript" type="text/javascript"> function DelayedSubmission() { var date = new Date(); initial_time = date.getTime(); if (typeof setInverval_Variable == 'undefined') { setInverval_Variable = setInterval(DelayedSubmission_Check, 50); } } function DelayedSubmission_Check() { var date = new Date(); check_time = date.getTime(); var limit_ms=check_time-initial_time; if (limit_ms > 800) { //Change value in milliseconds alert("insert your function"); //Insert your function clearInterval(setInverval_Variable); delete setInverval_Variable; } } </head> <body> <input type="search" onkeyup="DelayedSubmission()" id="field_id" style="WIDTH: 100px; HEIGHT: 25px;" /> </body> </html> |
不确定我的需求是否有点奇怪,但我需要类似的东西,这就是我最终使用的东西:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | $('input.update').bind('sync', function() { clearTimeout($(this).data('timer')); $.post($(this).attr('data-url'), {value: $(this).val()}, function(x) { if(x.success != true) { triggerError(x.message); } }, 'json'); }).keyup(function() { clearTimeout($(this).data('timer')); var val = $.trim($(this).val()); if(val) { var $this = $(this); var timer = setTimeout(function() { $this.trigger('sync'); }, 2000); $(this).data('timer', timer); } }).blur(function() { clearTimeout($(this).data('timer')); $(this).trigger('sync'); }); |
这允许我在我的应用程序中包含这样的元素:
1 | <input type="text" data-url="/controller/action/" class="update"> |
当用户"完成输入"(2秒内没有动作)或转到另一个字段(模糊了元素)时会更新
一旦检测到文本框上的焦点,在按键上执行超时检查,并在每次触发时重置它。
超时完成后,执行ajax请求。
为什么不使用onfocusout?
https://www.w3schools.com/jsreF/event_onfocusout.asp
如果它是一个表单,它们将始终保留每个输入字段的焦点,以便单击提交按钮,因此您知道没有输入将错过获取其onfocusout事件处理程序调用。
每页多个计时器
所有其他答案仅适用于一个控件(包括我的其他答案)。
如果每页有多个控件(例如在购物车中),则只会调用用户输入内容的最后一个控件。在我的情况下,这肯定不是希望的行为 - 每个控件应该有自己的计时器。
要解决此问题,您只需将ID传递给函数并维护timeoutHandles字典,如下面的代码所示:
功能声明:
1 2 3 4 5 6 7 8 9 10 | var delayUserInput = (function () { var timeoutHandles = {}; return function (id, callback, ms) { if (timeoutHandles[id]) { clearTimeout(timeoutHandles[id]); } timeoutHandles[id] = setTimeout(callback, ms); }; })(); |
功能用途:
1 2 3 | delayUserInput('yourID', function () { //do some stuff }, 1000); |
如果您需要等到用户完成输入后使用简单:
1 2 3 | $(document).on('change','#PageSize', function () { //Do something after new value in #PageSize }); |
使用ajax调用完成示例 - 这适用于我的寻呼机 - 每个列表的项目数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | $(document).ready(function () { $(document).on('change','#PageSize', function (e) { e.preventDefault(); var page = 1; var pagesize = $("#PageSize").val(); var q = $("#q").val(); $.ajax({ url: '@Url.Action("IndexAjax","Materials", new { Area ="TenantManage" })', data: { q: q, pagesize: pagesize, page: page }, type: 'post', datatype:"json", success: function (data) { $('#tablecontainer').html(data); // toastr.success('Pager has been changed',"Success!"); }, error: function (jqXHR, exception) { ShowErrorMessage(jqXHR, exception); } }); }); }); |
如果您要查找特定长度(例如邮政编码字段):
1 2 3 4 5 | $("input").live("keyup", function( event ){ if(this.value.length == this.getAttribute('maxlength')) { //make ajax request here after. } }); |
哇,即使3条评论都是非常正确的!
空输入不是跳过函数调用的原因,例如我在重定向之前从url中删除了废弃参数
必须使用
您可以使用
(我的决定)我使用匿名函数而不是