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

ajs*_*sie 618 javascript jquery

我有一个搜索领域.现在它搜索每个keyup.因此,如果有人键入"Windows",它将使用AJAX搜索每个键盘:"W","Wi","Win","Wind","Windo","Window","Windows".

我希望有一个延迟,所以它只在用户停止键入200毫秒时搜索.

在函数中没有这个选项keyup,我试过了setTimeout,但它没有用.

我怎样才能做到这一点?

CMS*_*CMS 1076

我将这个小函数用于相同的目的,在用户停止键入指定的时间后或在以高速率触发的事件中执行函数,例如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));
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

这个怎么运作:

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

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

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

  • 另一种选择:http://github.com/bgrins/bindWithDelay/blob/master/bindWithDelay.js.它几乎与您描述的方式相同,我发现自己使用该模式很多,因此将其实现为jQuery插件,以使语法更简单.这是一个演示页面:http://briangrinstead.com/files/bindWithDelay/ (63认同)
  • 但是,如果我调用两个或更多需要单独延迟的不同函数,则这不起作用.我做了这个解决方案而不是http://stackoverflow.com/a/30503848/1834212 (6认同)
  • 我推荐在顶部评论中链接的'bindWithDelay'插件.但我建议@Hazerider对这个问题的回答(下面 - http://stackoverflow.com/a/19259625/368896),这比这个答案更好,值得研究,以了解简单,光滑的绑定背后的想法,允许不同的计时器不同的元素 - 与上面的插件代码中使用的原理相同,但更容易理解. (4认同)
  • 我最初硬编码了字母的数量,这种方法很顺利,因为糖蜜(没有硫化) (2认同)
  • 当我将它与$ .post()一起使用时,它会同时发送所有输入的内容,但它会像我输入密钥一样多次发送它.有没有办法在超时结束时发送? (2认同)

RHi*_*cke 59

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

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

或者使用匿名函数:

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

    //ajax code

  }, 200);  
}   
Run Code Online (Sandbox Code Playgroud)


Pas*_*ver 34

CMS回答的另一个细微增强.要轻松允许单独延迟,您可以使用以下内容:

function makeDelay(ms) {
    var timer = 0;
    return function(callback){
        clearTimeout (timer);
        timer = setTimeout(callback, ms);
    };
};
Run Code Online (Sandbox Code Playgroud)

如果你想重复使用相同的延迟,那就行了

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

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

$(selector1).on('keyup', function() {makeDelay(250)(someCallback);});
$(selector2).on('keyup', function() {makeDelay(250)(someCallback);});
Run Code Online (Sandbox Code Playgroud)

  • 有趣的是,在我写这篇评论的那天,有超过 600 个赞成票的解决方案不如这个只有 2 个赞成票(包括我的)的答案好。显然更胜一筹,因为它支持多个可以共享或不共享延迟的小部件。优秀的答案。 (2认同)

mel*_*yal 28

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

var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);
Run Code Online (Sandbox Code Playgroud)


Gat*_*ten 14

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

在包含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);
Run Code Online (Sandbox Code Playgroud)

并简单地使用这样:

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

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


Mig*_*uel 11

使用标签延迟多功能调用

这是我使用的解决方案.它会延迟你想要的任何函数的执行.它可以是keydown搜索查询,也许是快速点击上一个或下一个按钮(否则如果连续快速点击则会发送多个请求,并且最终不会被使用).这使用一个全局对象来存储每个执行时间,并将其与最新请求进行比较.

因此,结果是实际上只会调用最后一次单击/操作,因为这些请求存储在队列中,如果队列中不存在具有相同标签的其他请求,则在调用X毫秒之后!

function delay_method(label,callback,time){
    if(typeof window.delayed_methods=="undefined"){window.delayed_methods={};}  
    delayed_methods[label]=Date.now();
    var t=delayed_methods[label];
    setTimeout(function(){ if(delayed_methods[label]!=t){return;}else{  delayed_methods[label]=""; callback();}}, time||500);
  }
Run Code Online (Sandbox Code Playgroud)

您可以设置自己的延迟时间(可选,默认为500毫秒).并以"闭包方式"发送函数参数.

例如,如果要调用波纹管功能:

function send_ajax(id){console.log(id);}
Run Code Online (Sandbox Code Playgroud)

要防止多个send_ajax请求,请使用以下命令延迟它们:

delay_method( "check date", function(){ send_ajax(2); } ,600);

只有在600毫秒时间范围内没有其他请求时,才会触发使用标签"检查日期"的每个请求.这个参数是可选的

标签独立性(调用相同的目标函数)但同时运行:

delay_method("check date parallel", function(){send_ajax(2);});
delay_method("check date", function(){send_ajax(2);});
Run Code Online (Sandbox Code Playgroud)

调用相同功能但由于标签不同而导致它们独立延迟


小智 11

jQuery

var timeout = null;
$('#input').keyup(function() {
  clearTimeout(timeout);
  timeout = setTimeout(() => {
      console.log($(this).val());
  }, 1000);
});
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<input type="text" id="input" placeholder="Type here..."/>
Run Code Online (Sandbox Code Playgroud)

纯Javascript:

let input = document.getElementById('input');
let timeout = null;

input.addEventListener('keyup', function (e) {
    clearTimeout(timeout);
    timeout = setTimeout(function () {
        console.log('Value:', input.value);
    }, 1000);
});
Run Code Online (Sandbox Code Playgroud)
<input type="text" id="input" placeholder="Type here..."/>
Run Code Online (Sandbox Code Playgroud)


小智 7

此函数从Gaten的回答中扩展了函数,以便返回元素:

$.fn.delayKeyup = function(callback, ms){
    var timer = 0;
    var el = $(this);
    $(this).keyup(function(){                   
    clearTimeout (timer);
    timer = setTimeout(function(){
        callback(el)
        }, ms);
    });
    return $(this);
};

$('#input').delayKeyup(function(el){
    //alert(el.val());
    // Here I need the input element (value for ajax call) for further process
},1000);
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/Us9bu/2/


Roy*_*hoa 7

如果有人喜欢延迟相同的功能,并且没有外部变量,他可以使用下一个脚本:

function MyFunction() {

    //Delaying the function execute
    if (this.timer) {
        window.clearTimeout(this.timer);
    }
    this.timer = window.setTimeout(function() {

        //Execute the function code here...

    }, 500);
}
Run Code Online (Sandbox Code Playgroud)


Hol*_*ger 7

超级简单的方法,旨在在用户输入完文本字段后运行功能...

<script type="text/javascript">
$(document).ready(function(e) {
    var timeout;
    var delay = 2000;   // 2 seconds

    $('.text-input').keyup(function(e) {
        console.log("User started typing!");
        if(timeout) {
            clearTimeout(timeout);
        }
        timeout = setTimeout(function() {
            myFunction();
        }, delay);
    });

    function myFunction() {
        console.log("Executing function for user!");
    }
});
</script>

<textarea name="text-input" class="text-input"></textarea>
Run Code Online (Sandbox Code Playgroud)


Sag*_*ala 6

这对我有用,我会延迟搜索逻辑操作,并检查该值是否与在文本字段中输入的值相同.如果值相同,那么我继续执行与搜索值相关的数据的操作.

$('#searchText').on('keyup',function () {
    var searchValue = $(this).val();
    setTimeout(function(){
        if(searchValue == $('#searchText').val() && searchValue != null && searchValue != "") {
           // logic to fetch data based on searchValue
        }
        else if(searchValue == ''){
           // logic to load all the data
        }
    },300);
});
Run Code Online (Sandbox Code Playgroud)


jsz*_*oja 5

我很惊讶没有人提到CMS中的多个输入问题非常好的剪辑.

基本上,您必须为每个输入单独定义延迟变量.否则,如果sb将文本放到第一个输入并快速跳转到其他输入并开始输入,则不会调用第一个回调!

根据其他答案,请参阅下面的代码:

(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);
Run Code Online (Sandbox Code Playgroud)

此解决方案将setTimeout引用保留在input的delayTimer变量中.它还将元素的引用传递给fazzyx建议的回调.

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