我有一个搜索域。现在它会搜索每一个按键。所以如果有人输入“Windows”,它会用AJAX搜索每个键:“W”,“Wi”,“Win”,“Wind”,“Windo”,“Window”,“Windows”。

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

在keyup函数中没有这个选项,我尝试了setTimeout,但它不起作用。

我该怎么做呢?


当前回答

如果你想在一段时间后做一些事情,并在特定的事件(如keyup)后重置定时器,最好的解决方案是使用clearTimeout和setTimeout方法:

// declare the timeout variable out of the event listener or in the global scope
var timeout = null;

$(".some-class-or-selector-to-bind-event").keyup(function() {
    clearTimeout(timout); // this will clear the recursive unneccessary calls
    timeout = setTimeout(() => {
         // do something: send an ajax or call a function here
    }, 2000);
    // wait two seconds

});

其他回答

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);});

我使用这个小函数也是出于同样的目的,在用户停止输入一段特定的时间后,或者在以高速率触发的事件中执行一个函数,比如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元素)。

更新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插件。

使用jQuery插件bindWithDelay:

element.bindWithDelay(eventType, [ eventData ], handler(eventObject), timeout, throttle)

我很惊讶,没有人提到多重输入的问题在CMS的非常好的剪辑。

基本上,你必须为每个输入分别定义延迟变量。否则,如果有人把文本放在第一个输入,并迅速跳转到其他输入并开始输入,第一个的回调将不会被调用!

下面是我根据其他答案编写的代码:

(function($) {
    /**
     * KeyUp with delay event setup
     * 
     * @link http://stackoverflow.com/questions/1909441/jquery-keyup-delay#answer-12581187
     * @param function callback
     * @param int ms
     */
    $.fn.delayKeyup = function(callback, ms){
            $(this).keyup(function( event ){
                var srcEl = event.currentTarget;
                if( srcEl.delayTimer )
                    clearTimeout (srcEl.delayTimer );
                srcEl.delayTimer = setTimeout(function(){ callback( $(srcEl) ); }, ms);
            });

        return $(this);
    };
})(jQuery);

该解决方案将setTimeout引用保留在输入的delayTimer变量中。它还像fazzyx建议的那样将元素的引用传递给回调。

在IE6, 8(comp - 7), 8和Opera 12.11中测试。

如果你想在类型完成后搜索,使用一个全局变量来保存setTimout调用返回的超时,如果它还没有发生,就用clearTimeout取消它,这样它就不会触发超时,除非在最后一个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);  
}