【问题标题】:How to trigger an event in input text after I stop typing/writing?停止输入/书写后如何触发输入文本中的事件?
【发布时间】:2012-12-12 02:33:12
【问题描述】:

我想在我停止在输入文本框中输入(而不是在输入时)字符后触发一个事件。

我试过了:

$('input#username').keypress(function() {
    var _this = $(this); // copy of this object for further usage

    setTimeout(function() {
        $.post('/ajax/fetch', {
            type: 'username',
            value: _this.val()
        }, function(data) {
            if(!data.success) {
                // continue working
            } else {
                // throw an error
            }
        }, 'json');
    }, 3000);
});

但是这个例子会为每个输入的字符产生一个超时,如果我输入 20 个字符,我会收到大约 20 个 AJAX 请求。

On this fiddle 我用一个简单的警报而不是 AJAX 来演示同样的问题。

是否有解决方案,或者我只是为此使用了不好的方法?

【问题讨论】:

  • 恐怕javascript没有提供一个事件,当用户停止输入输入字段时,您可以收到通知。为什么需要它?
  • 从例子中不是很明显吗?我想触发一个事件“当最终用户停止输入时”,而不是发送 20 个请求
  • 除非用户手动提交或更改字段,否则无法判断用户何时真正完成输入。您如何知道用户是否在句子中间暂停并等待 5 分钟再输入更多内容?一种可能的解决方案是使用 .blur() 并在用户焦点离开该字段时发送。
  • 上面的cmets都傻了。这是一个常见的用例:当用户完成调整窗口大小、缩放地图、拖动、打字时,我想要一个事件……基本上,用户的任何连续动作都需要转化为我们的数字世界。即使是单次击键也会遇到这个问题:当你敲击一个键时,它实际上会“弹跳”,不仅会创建 1 个击键事件,而且会创建很多。您计算机的硬件或操作系统会删除这些额外事件,这就是为什么我们会产生离散击键事件的错觉。这被称为“去抖动”,这就是 OP 所需要的。
  • 对反应用户的警告:stackoverflow.com/a/28046731/57883

标签: jquery timeout keypress typeahead debouncing


【解决方案1】:

您必须使用setTimeout(就像您一样)但还要存储参考,以便您可以继续重置限制。比如:

//
// $('#element').donetyping(callback[, timeout=1000])
// Fires callback when a user has finished typing. This is determined by the time elapsed
// since the last keystroke and timeout parameter or the blur event--whichever comes first.
//   @callback: function to be called when even triggers
//   @timeout:  (default=1000) timeout, in ms, to to wait before triggering event if not
//              caused by blur.
// Requires jQuery 1.7+
//
;(function($){
    $.fn.extend({
        donetyping: function(callback,timeout){
            timeout = timeout || 1e3; // 1 second default timeout
            var timeoutReference,
                doneTyping = function(el){
                    if (!timeoutReference) return;
                    timeoutReference = null;
                    callback.call(el);
                };
            return this.each(function(i,el){
                var $el = $(el);
                // Chrome Fix (Use keyup over keypress to detect backspace)
                // thank you @palerdot
                $el.is(':input') && $el.on('keyup keypress paste',function(e){
                    // This catches the backspace button in chrome, but also prevents
                    // the event from triggering too preemptively. Without this line,
                    // using tab/shift+tab will make the focused element fire the callback.
                    if (e.type=='keyup' && e.keyCode!=8) return;
                    
                    // Check if timeout has been set. If it has, "reset" the clock and
                    // start over again.
                    if (timeoutReference) clearTimeout(timeoutReference);
                    timeoutReference = setTimeout(function(){
                        // if we made it here, our timeout has elapsed. Fire the
                        // callback
                        doneTyping(el);
                    }, timeout);
                }).on('blur',function(){
                    // If we can, fire the event since we're leaving the field
                    doneTyping(el);
                });
            });
        }
    });
})(jQuery);

$('#example').donetyping(function(){
  $('#example-output').text('Event last fired @ ' + (new Date().toUTCString()));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<input type="text" id="example" />
<p id="example-output">Nothing yet</p>

这将在以下时间执行:

  1. 超时已过,或
  2. 用户切换字段(blur 事件)

(以先到者为准)

【讨论】:

  • @Brad:这个 jquery 解决方案工作正常,除了在最新的 chrome (38.0.2125.111) 中未检测到输入框中键入的退格键。只有将其更改为 keyup 才有效。您可能需要检查并适当地修改代码。
  • 感谢这个插件 - 效果很好。我必须进行一项调整,因为当有人将某些内容粘贴到输入字段中时它不起作用。我编辑了以下行以包含 paste -- $el.is(':input') &amp;&amp; $el.on('keyup keypress paste',function(e){
  • @Sangar82:现在应该(虽然我有点困惑,但 ctrl+v 应该被按键捕获——除非你是右键单击->粘贴?
  • @BradChristie 如果使用 DEL 键删除文本,则无法在一般 Android Chrome 或桌面 Chrome 上运行
  • @KenIngram 分号是为了防止它与其他模块一起缩小,它可以避免无效的语句(来自不完整的先前脚本)。至于上下文,它扩展了 jQuery 库以添加 donetyping 扩展方法(类似于以前的 jquery 迭代中的 .click(在 .on(click', ...) 成为标准之前)。希望有所帮助。
【解决方案2】:

在我看来,当用户不专注于输入时,他就会停止写作。为此,您有一个名为“blur”的函数,它可以处理like

【讨论】:

  • 错了! blur 是焦点在特定输入字段上丢失时的事件。我需要确定何时在我尝试触发事件的字段下未使用键盘。
【解决方案3】:

解决方案:

这里是解决方案。在用户停止输入指定的时间后执行函数:

var delay = (function(){
  var timer = 0;
  return function(callback, ms){
  clearTimeout (timer);
  timer = setTimeout(callback, ms);
 };
})();

用法

$('input').keyup(function() {
  delay(function(){
    alert('Hi, func called');
  }, 1000 );
});

【讨论】:

  • 有人可以向我解释这是如何工作的吗?似乎立即调用函数表达式位是这里的主要内容,但我认为我不明白发生了什么。
  • 等一下...这是否设置为 IIFE 只是为了以包含的方式设置计时器变量(而不是在 delay 变量之外单独设置?然后剩下的只是一个普通的函数表达式?
【解决方案4】:

你需要去抖动!

这是jQuery plugin,这里是您需要了解的有关debounce 的所有信息。如果您是从 Google 来到这里的,并且 Underscore 已进入您应用的 JSoup,则它已 debounce baked right in

【讨论】:

    【解决方案5】:

    你可以使用 underscore.js “去抖动”

    $('input#username').keypress( _.debounce( function(){<your ajax call here>}, 500 ) );
    

    这意味着您的函数调用将在按键 500 毫秒后执行。但是如果你在 500ms 之前按下另一个键(触发另一个 keypress 事件),之前的函数执行将被忽略(去抖动),新的函数将在新的 500ms 计时器后执行。

    更多信息, 使用 _.debounce(func,timer,true) 将意味着将执行第一个函数,并且所有其他具有后续 500 毫秒计时器的按键事件将被忽略。

    【讨论】:

      【解决方案6】:

      我一直在寻找一个简单的 HTML/JS 代码,但没有找到。然后,我使用onkeyup="DelayedSubmission()"编写了下面的代码。

      <!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><title>Submit after typing finished</title>
      <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;
          }
      }
      
      </script>
      </head>
      <body>
      
      <input type="search" onkeyup="DelayedSubmission()" id="field_id" style="WIDTH: 100px; HEIGHT: 25px;" />
      
      </body>
      </html>
      

      【讨论】:

        【解决方案7】:

        清洁的解决方案:

        $.fn.donetyping = function(callback, delay){
          delay || (delay = 1000);
          var timeoutReference;
          var doneTyping = function(elt){
            if (!timeoutReference) return;
            timeoutReference = null;
            callback(elt);
          };
        
          this.each(function(){
            var self = $(this);
            self.on('keyup',function(){
              if(timeoutReference) clearTimeout(timeoutReference);
              timeoutReference = setTimeout(function(){
                doneTyping(self);
              }, delay);
            }).on('blur',function(){
              doneTyping(self);
            });
          });
        
          return this;
        };
        

        【讨论】:

          【解决方案8】:

          我做了一些简单的plugin 就是这样做的。它需要的代码比提议的解决方案少得多,而且非常轻巧 (~0,6kb)

          首先你创建Bid 对象,而不是任何时候bumped。每个 bump 都会延迟触发 Bid 回调,直到下一个给定的时间量。

          var searchBid = new Bid(function(inputValue){
              //your action when user will stop writing for 200ms. 
              yourSpecialAction(inputValue);
          }, 200); //we set delay time of every bump to 200ms
          

          Bid 对象准备好时,我们需要以某种方式bump 它。让我们附加碰撞到keyupevent

          $("input").keyup(function(){
              searchBid.bump( $(this).val() ); //parameters passed to bump will be accessable in Bid callback
          });
          

          这里发生的是:

          每次用户按键时,出价都会在接下来的 200 毫秒内“延迟”(碰撞)。如果 200 毫秒后没有再次“碰撞”,则会触发回调。

          此外,您还有 2 个额外的功能用于停止出价(例如,如果用户按下 esc 或单击外部输入)以及用于立即完成和触发回调(例如,当用户按下回车键时):

          searchBid.stop();
          searchBid.finish(valueToPass);
          

          【讨论】:

            【解决方案9】:

            当您只想重置时钟时,为什么要这么做?

            var clockResetIndex = 0 ;
            // this is the input we are tracking
            var tarGetInput = $('input#username');
            
            tarGetInput.on( 'keyup keypress paste' , ()=>{
                // reset any privious clock:
                if (clockResetIndex !== 0) clearTimeout(clockResetIndex);
            
                // set a new clock ( timeout )
                clockResetIndex = setTimeout(() => {
                    // your code goes here :
                    console.log( new Date() , tarGetInput.val())
                }, 1000);
            });
            

            如果您正在使用 wordpress ,那么您需要将所有这些代码包装在里面 一个 jQuery 块:

            jQuery(document).ready(($) => {
                /**
                 * @name 'navSearch' 
                 * @version 1.0
                 * Created on: 2018-08-28 17:59:31
                 * GMT+0530 (India Standard Time)
                 * @author : ...
                 * @description ....
                 */
                    var clockResetIndex = 0 ;
                    // this is the input we are tracking
                    var tarGetInput = $('input#username');
            
                    tarGetInput.on( 'keyup keypress paste' , ()=>{
                        // reset any privious clock:
                        if (clockResetIndex !== 0) clearTimeout(clockResetIndex);
            
                        // set a new clock ( timeout )
                        clockResetIndex = setTimeout(() => {
                            // your code goes here :
                            console.log( new Date() , tarGetInput.val())
                        }, 1000);
                    });
            });
            

            【讨论】:

            • 如果你想扩展jquery并且想在多个输入元素中使用这个方法,那么认可的答案就是你要找的答案。
            【解决方案10】:

            您应该将setTimeout 分配给一个变量并使用clearTimeout 在按键时将其清除。

            var timer = '';
            
            $('input#username').keypress(function() {
              clearTimeout(timer);
              timer = setTimeout(function() {
                //Your code here
              }, 3000); //Waits for 3 seconds after last keypress to execute the above lines of code
            });
            

            Fiddle

            希望这会有所帮助。

            【讨论】:

              【解决方案11】:

              在您的 html 的 &lt;input&gt; 中使用属性 onkeyup="myFunction()"。

              【讨论】:

                【解决方案12】:

                我们可以在 react 中使用 useDebouncedCallback 来执行这个任务。

                导入 { useDebouncedCallback } from 'use-debounce'; - 如果未安装,请安装相同的 npm packge

                const [searchText, setSearchText] = useState('');
                
                const onSearchTextChange = value => {
                    setSearchText(value);
                  };
                
                //call search api
                  const [debouncedOnSearch] = useDebouncedCallback(searchIssues, 500);
                  useEffect(() => {
                    debouncedOnSearch(searchText);
                  }, [searchText, debouncedOnSearch]);
                

                【讨论】:

                  【解决方案13】:

                  这就是我使用的 formControl。它对我有用。

                  this.form.controls[`text`].valueChanges
                    .pipe(debounceTime(500), distinctUntilChanged())
                    .subscribe((finalText) => {
                      yourMethod(finalText);
                  });
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2021-11-25
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-06-16
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多