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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1909441/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 21:51:25  来源:igfitidea点击:

How to delay the .keyup() handler until the user stops typing?

javascriptjquery

提问by ajsie

I've got a search field. Right now it searches for every keyup. So if someone types “Windows”, it will make a search with AJAX for every keyup: “W”, “Wi”, “Win”, “Wind”, “Windo”, “Window”, “Windows”.

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

I want to have a delay, so it only searches when the user stops typing for 200 ms.

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

There is no option for this in the keyupfunction, and I have tried setTimeout, but it didn't work.

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

How can I do that?

我怎样才能做到这一点?

回答by CMS

I use this small function for the same purpose, executing a function after the user has stopped typing for a specified amount of time or in events that fire at a high rate, like resize:

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

How it works:

这个怎么运作:

The delayfunction will return a wrapped function that internally handles an individual timer, in each execution the timer is restarted with the time delay provided, if multiple executions occur before this time passes, the timer will just reset and start again.

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

When the timer finally ends, the callback function is executed, passing the original context and arguments (in this example, the jQuery's event object, and the DOM element as this).

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

UPDATE 2019-05-16

更新 2019-05-16

I have re-implemented the function using ES5 and ES6 features for modern environments:

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

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

The implementation is covered with a set of tests.

该实现包含一组测试

For something more sophisticated, give a look to the jQuery Typewatchplugin.

对于更复杂的内容,请查看 jQuery Typewatch插件。

回答by RHicke

If you want to search after the type is done use a global variable to hold the timeout returned from your setTimoutcall and cancel it with a clearTimeoutif it hasn't yet happend so that it won't fire the timeout except on the last keyupevent

如果您想在类型完成后进行搜索,请使用全局变量来保存从您的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
}

Or with an anonymous function :

或者使用匿名函数:

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

    //ajax code

  }, 200);  
}   

回答by Paschover

Another slight enhancement on CMS's answer. To easily allow for separate delays, you can use the following:

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

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

If you want to reuse the same delay, just do

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

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

If you want separate delays, you can do

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

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

回答by meleyal

You could also look at underscore.js, which provides utility methods like debounce:

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

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

回答by Gaten

Based on the answer of CMS, I made this :

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

Put the code below after include jQuery :

将下面的代码放在 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);

And simply use like this :

只需像这样使用:

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

Careful : the $(this) variable in the function passed as a parameter does not match input

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

回答by Miguel

Delay Multi Function Calls using Labels

使用标签延迟多功能调用

This is the solution i work with. It will delay the execution on ANY function you want. It can be the keydown search query, maybe the quick click on previous or next buttons ( that would otherwise send multiple request if quickly clicked continuously , and be not used after all). This uses a global object that stores each execution time, and compares it with the most current request.

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

So the result is that only that last click / action will actually be called, because those requests are stored in a queue, that after the X milliseconds is called if no other request with the same label exists in the queue!

所以结果是只有最后一次点击/动作才会被实际调用,因为这些请求存储在一个队列中,如果队列中不存在其他具有相同标签的请求,则在 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);
  }

You can set your own delay time ( its optional, defaults to 500ms). And send your function arguments in a "closure fashion".

您可以设置自己的延迟时间(可选,默认为 500ms)。并以“关闭方式”发送您的函数参数。

For example if you want to call the bellow function:

例如,如果要调用波纹管函数:

function send_ajax(id){console.log(id);}

To prevent multiple send_ajax requests, you delay them using:

为了防止多个 send_ajax 请求,您可以使用以下方法延迟它们

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

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

Every request that uses the label "check date" will only be triggered if no other request is made in the 600 miliseconds timeframe. This argument is optional

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

Label independency (calling the same target function) but run both:

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

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

Results in calling the same function but delay them independently because of their labels being different

导致调用相同的函数但由于它们的标签不同而独立延迟它们

回答by Roy Shoa

If someone like to delay the same function, and without external variable he can use the next script:

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

function MyFunction() {

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

        //Execute the function code here...

    }, 500);
}

回答by HoldOffHunger

Super simple approach, designed to run a function after a user has finished typing in a text field...

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

<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>

回答by fazzyx

This function extends the function from Gaten's answer a bit in order to get the element back:

此函数对 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);

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

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

回答by Sagar Gala

This worked for me where I delay the search logic operation and make a check if the value is same as entered in text field. If value is same then I go ahead and perform the operation for the data related to search value.

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

$('#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);
});