如何延迟 .keyup() 处理程序直到用户停止输入?

IT技术 javascript jquery
2021-01-17 06:41:30

我有一个搜索字段。现在它搜索每个keyup。因此,如果有人输入“Windows”,它将使用 AJAX 搜索每个键:“W”、“Wi”、“Win”、“Wind”、“Windo”、“Window”、“Windows”。

我想要延迟,所以它只在用户停止输入 200 毫秒时搜索。

keyup函数中没有这个选项,我试过setTimeout,但没有用。

我怎样才能做到这一点?

6个回答

我将这个小函数用于相同的目的,在用户停止输入指定的时间后或在高速触发的事件中执行一个函数,例如resize

function delay(callback, ms) {
  var timer = 0;
  return function() {
    var context = this, args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function () {
      callback.apply(context, args);
    }, ms || 0);
  };
}


// Example usage:

$('#input').keyup(delay(function (e) {
  console.log('Time elapsed!', this.value);
}, 500));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label for="input">Try it:
<input id="input" type="text" placeholder="Type something here..."/>
</label>

这个怎么运作:

delay函数将返回一个在内部处理单个计时器的包装函数,在每次执行中,计时器以提供的时间延迟重新启动,如果在此时间过去之前发生多次执行,计时器将重置并重新启动。

当计时器最终结束时,将执行回调函数,传递原始上下文和参数(在此示例中,jQuery 的事件对象和 DOM 元素为this)。

更新 2019-05-16

我已经使用 ES5 和 ES6 特性为现代环境重新实现了该功能:

function delay(fn, ms) {
  let timer = 0
  return function(...args) {
    clearTimeout(timer)
    timer = setTimeout(fn.bind(this, ...args), ms || 0)
  }
}

该实现包含一组测试

对于更复杂的东西,请查看 jQuery Typewatch插件。

如果用户按下回车键,如何立即立即执行回调函数?
2021-03-21 06:41:30
另一种选择:github.com/bgrins/bindWithDelay/blob/master/bindWithDelay.js它的工作方式与您描述的几乎相同,我只是发现自己经常使用该模式,因此将其实现为 jQuery 插件以使语法更简单。这是一个演示页面:briangrinstead.com/files/bindWithDelay
2021-04-06 06:41:30

如果您想在类型完成后进行搜索,请使用全局变量来保存从您的setTimout调用返回的超时,并在clearTimeout尚未发生时使用 a 取消它,这样除了最后一个keyup事件外,它不会触发超时

var globalTimeout = null;  
$('#id').keyup(function(){
  if(globalTimeout != null) clearTimeout(globalTimeout);  
  globalTimeout =setTimeout(SearchFunc,200);  
}   
function SearchFunc(){  
  globalTimeout = null;  
  //ajax code
}

或者使用匿名函数:

var globalTimeout = null;  
$('#id').keyup(function() {
  if (globalTimeout != null) {
    clearTimeout(globalTimeout);
  }
  globalTimeout = setTimeout(function() {
    globalTimeout = null;  

    //ajax code

  }, 200);  
}   

对 CMS 答案的另一个轻微改进。要轻松地允许单独的延迟,您可以使用以下内容:

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

如果您想重复使用相同的延迟,只需执行

var delay = makeDelay(250);
$(selector1).on('keyup', function() {delay(someCallback);});
$(selector2).on('keyup', function() {delay(someCallback);});

如果你想要单独的延迟,你可以这样做

$(selector1).on('keyup', function() {makeDelay(250)(someCallback);});
$(selector2).on('keyup', function() {makeDelay(250)(someCallback);});

您还可以查看underscore.js,它提供了像debounce这样的实用方法

var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);

根据 CMS 的回答,我做了这个:

将下面的代码放在 include jQuery 之后:

/*
 * delayKeyup
 * http://code.azerti.net/javascript/jquery/delaykeyup.htm
 * Inspired by CMS in this post : http://stackoverflow.com/questions/1909441/jquery-keyup-delay
 * Written by Gaten
 * Exemple : $("#input").delayKeyup(function(){ alert("5 secondes passed from the last event keyup."); }, 5000);
 */
(function ($) {
    $.fn.delayKeyup = function(callback, ms){
        var timer = 0;
        $(this).keyup(function(){                   
            clearTimeout (timer);
            timer = setTimeout(callback, ms);
        });
        return $(this);
    };
})(jQuery);

只需像这样使用:

$('#input').delayKeyup(function(){ alert("5 secondes passed from the last event keyup."); }, 5000);

注意:作为参数传递的函数中的 $(this) 变量与输入不匹配