我有一个搜索字段。现在,它会搜索每个键。因此,如果有人键入“ Windows”,它将使用AJAX搜索每个键盘:“ W”,“ Wi”,“ Win”,“ Wind”,“ Windo”,“ Window”,“ Windows”。
我希望有一个延迟,因此它仅在用户停止键入200毫秒时才搜索。
keyup
函数中没有为此的选项,我已经尝试过了setTimeout
,但是没有用。
我怎样才能做到这一点?
我有一个搜索字段。现在,它会搜索每个键。因此,如果有人键入“ Windows”,它将使用AJAX搜索每个键盘:“ W”,“ Wi”,“ Win”,“ Wind”,“ Windo”,“ Window”,“ Windows”。
我希望有一个延迟,因此它仅在用户停止键入200毫秒时才搜索。
keyup
函数中没有为此的选项,我已经尝试过了setTimeout
,但是没有用。
我怎样才能做到这一点?
Answers:
我将这个小功能用于相同的目的,即在用户停止输入指定的时间后或在触发率很高的事件中执行一个功能,例如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
)。
我已经针对现代环境使用ES5和ES6功能重新实现了该功能:
function delay(fn, ms) {
let timer = 0
return function(...args) {
clearTimeout(timer)
timer = setTimeout(fn.bind(this, ...args), ms || 0)
}
}
该实现包含一组测试。
对于更复杂的内容,请看一下jQuery Typewatch插件。
如果您要在类型完成后进行搜索,请使用全局变量来保存从您的setTimout
调用返回的超时,并使用a来取消超时(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);
}
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);});
someApiCall
有所延迟,但仍然会触发多次-现在只是输入字段的最终值。
您还可以查看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)变量与输入不匹配
使用标签延迟多功能通话
这是我使用的解决方案。它将延迟您想要的任何功能的执行。它可以是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);
}
您可以设置自己的延迟时间(其可选时间,默认为500ms)。并以“关闭方式”发送函数参数。
例如,如果要调用波纹管功能:
function send_ajax(id){console.log(id);}
为了防止出现多个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);});
导致调用相同的函数,但由于其标签不同而使它们独立延迟
如果有人希望延迟相同的功能,并且没有外部变量,则可以使用下一个脚本:
function MyFunction() {
//Delaying the function execute
if (this.timer) {
window.clearTimeout(this.timer);
}
this.timer = window.setTimeout(function() {
//Execute the function code here...
}, 500);
}
超级简单的方法,旨在在用户输入完文本字段后运行功能...
<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>
该函数从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);
这对我有用,在这里我延迟了搜索逻辑操作,并检查该值是否与文本字段中输入的值相同。如果值相同,那么我将继续执行与搜索值相关的数据的操作。
$('#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);
});
我很惊讶,没有人提到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);
此解决方案将setTimeout引用保留在输入的delayTimer变量内。还将fazzyx建议将element的引用传递给回调。
在IE6、8(comp-7),8和Opera 12.11中进行了测试。
延迟功能可在每次键入时调用。 需要jQuery 1.7.1或更高版本
jQuery.fn.keyupDelay = function( cb, delay ){
if(delay == null){
delay = 400;
}
var timer = 0;
return $(this).on('keyup',function(){
clearTimeout(timer);
timer = setTimeout( cb , delay );
});
}
用法: $('#searchBox').keyupDelay( cb );
在CMS的答案的基础上,这是一种新的延迟方法,该方法在使用中保留了“ this”:
var delay = (function(){
var timer = 0;
return function(callback, ms, that){
clearTimeout (timer);
timer = setTimeout(callback.bind(that), ms);
};
})();
用法:
$('input').keyup(function() {
delay(function(){
alert('Time elapsed!');
}, 1000, this);
});
这是CMS的解决方案,但为我解决了一些关键问题:
var delay = (function() {
var timer = {}
, values = {}
return function(el) {
var id = el.form.id + '.' + el.name
return {
enqueue: function(ms, cb) {
if (values[id] == el.value) return
if (!el.value) return
var original = values[id] = el.value
clearTimeout(timer[id])
timer[id] = setTimeout(function() {
if (original != el.value) return // solves race condition
cb.apply(el)
}, ms)
}
}
}
}())
用法:
signup.key.addEventListener('keyup', function() {
delay(this).enqueue(300, function() {
console.log(this.value)
})
})
该代码以我喜欢的风格编写,您可能需要添加一堆分号。
注意事项:
this
按预期方式工作(如示例中所示)。setTimeout
。我使用的解决方案增加了另一层次的复杂性,例如,允许您取消执行,但这是一个良好的基础。
根据CMS的答案,它只忽略不会更改值的关键事件。
var delay = (function(){
var timer = 0;
return function(callback, ms){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
})();
var duplicateFilter=(function(){
var lastContent;
return function(content,callback){
content=$.trim(content);
if(content!=lastContent){
callback(content);
}
lastContent=content;
};
})();
$("#some-input").on("keyup",function(ev){
var self=this;
delay(function(){
duplicateFilter($(self).val(),function(c){
//do sth...
console.log(c);
});
}, 1000 );
})
将CMS答案与Miguel的答案相结合,可以生成一个健壮的解决方案,并发延迟。
var delay = (function(){
var timers = {};
return function (callback, ms, label) {
label = label || 'defaultTimer';
clearTimeout(timers[label] || 0);
timers[label] = setTimeout(callback, ms);
};
})();
当您需要独立延迟其他操作时,请使用第三个参数。
$('input.group1').keyup(function() {
delay(function(){
alert('Time elapsed!');
}, 1000, 'firstAction');
});
$('input.group2').keyup(function() {
delay(function(){
alert('Time elapsed!');
}, 1000, '2ndAction');
});
使用bindWithDelay jQuery插件:
element.bindWithDelay(eventType, [ eventData ], handler(eventObject), timeout, throttle)
这是我写的建议,可以处理您表单中的多个输入。
此函数获取输入字段的对象,并将其放入代码中
function fieldKeyup(obj){
// what you want this to do
} // fieldKeyup
这是实际的delayCall函数,负责多个输入字段
function delayCall(obj,ms,fn){
return $(obj).each(function(){
if ( typeof this.timer == 'undefined' ) {
// Define an array to keep track of all fields needed delays
// This is in order to make this a multiple delay handling
function
this.timer = new Array();
}
var obj = this;
if (this.timer[obj.id]){
clearTimeout(this.timer[obj.id]);
delete(this.timer[obj.id]);
}
this.timer[obj.id] = setTimeout(function(){
fn(obj);}, ms);
});
}; // delayCall
用法:
$("#username").on("keyup",function(){
delayCall($(this),500,fieldKeyup);
});
从ES6开始,也可以使用箭头函数语法。
在此示例中,代码keyup
在用户完成键入后将事件延迟400毫秒,然后才调用searchFunc
发出查询请求。
const searchbar = document.getElementById('searchBar');
const searchFunc = // any function
// wait ms (milliseconds) after user stops typing to execute func
const delayKeyUp = (() => {
let timer = null;
const delay = (func, ms) => {
timer ? clearTimeout(timer): null
timer = setTimeout(func, ms)
}
return delay
})();
searchbar.addEventListener('keyup', (e) => {
const query = e.target.value;
delayKeyUp(() => {searchFunc(query)}, 400);
})
jQuery的:
var timeout = null;
$('#input').keyup(function() {
clearTimeout(timeout);
timeout = setTimeout(() => {
console.log($(this).val());
}, 1000);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<input type="text" id="input" placeholder="Type here..."/>
纯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);
});
<input type="text" id="input" placeholder="Type here..."/>
好吧,我还编写了一段代码来限制由Keyup / Keydown引起的高频ajax请求。看一下这个:
https://github.com/raincious/jQueue
这样查询吗?
var q = new jQueue(function(type, name, callback) {
return $.post("/api/account/user_existed/", {Method: type, Value: name}).done(callback);
}, 'Flush', 1500); // Make sure use Flush mode.
并这样绑定事件:
$('#field-username').keyup(function() {
q.run('Username', this.val(), function() { /* calling back */ });
});
用户lodash javascript库并使用_.debounce函数
changeName: _.debounce(function (val) {
console.log(val)
}, 1000)
// Get an global variable isApiCallingInProgress
// check isApiCallingInProgress
if (!isApiCallingInProgress) {
// set it to isApiCallingInProgress true
isApiCallingInProgress = true;
// set timeout
setTimeout(() => {
// Api call will go here
// then set variable again as false
isApiCallingInProgress = false;
}, 1000);
}