我有一个搜索域。现在它会搜索每一个按键。所以如果有人输入“Windows”,它会用AJAX搜索每个键:“W”,“Wi”,“Win”,“Wind”,“Windo”,“Window”,“Windows”。
我想有一个延迟,所以它只在用户停止输入200毫秒时搜索。
在keyup函数中没有这个选项,我尝试了setTimeout,但它不起作用。
我该怎么做呢?
我有一个搜索域。现在它会搜索每一个按键。所以如果有人输入“Windows”,它会用AJAX搜索每个键:“W”,“Wi”,“Win”,“Wind”,“Windo”,“Window”,“Windows”。
我想有一个延迟,所以它只在用户停止输入200毫秒时搜索。
在keyup函数中没有这个选项,我尝试了setTimeout,但它不起作用。
我该怎么做呢?
当前回答
这是一个沿着CMS的路线的解决方案,但为我解决了几个关键问题:
支持多输入,延迟可以并发运行。 忽略没有改变值的键事件(如Ctrl, Alt+Tab)。 解决竞态条件(当执行回调且值已更改时)。
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)
})
})
代码以我喜欢的风格编写,您可能需要添加一堆分号。
需要记住的事情:
一个唯一的id是基于表单id和输入名称生成的,所以它们必须是定义的和唯一的,或者您可以根据您的情况进行调整。 Delay返回一个易于扩展以满足自己需要的对象。 用于延迟的原始元素被绑定到回调,因此这可以按预期工作(如示例所示)。 在第二次验证中忽略空值。 注意enqueue,它首先需要毫秒,我更喜欢这样,但您可能想要切换参数以匹配setTimeout。
我使用的解决方案增加了另一个层次的复杂性,例如,允许您取消执行,但这是一个很好的基础。
其他回答
将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');
});
今天看到这个有点晚,但我想把它放在这里,以防有人需要。只需将函数分离以使其可重用。下面的代码在输入stop后将等待1/2秒。
var timeOutVar
$(selector).on('keyup', function() {
clearTimeout(timeOutVar);
timeOutVar= setTimeout(function(){ console.log("Hello"); }, 500);
});
在ES6中,也可以使用箭头函数语法。
在本例中,在调用searchFunc发出查询请求之前,在用户完成输入之后,代码将keyup事件延迟400ms。
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);
})
更新后的Typescript版本:
const delayKeyUp = (() => {
let timer: NodeJS.Timeout;
return (func: Function, ms: number) => {
timer ? clearTimeout(timer) : null;
timer = setTimeout(() => func(), ms);
};
})();
延迟函数调用每个按键。 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);
我使用这个小函数也是出于同样的目的,在用户停止输入一段特定的时间后,或者在以高速率触发的事件中执行一个函数,比如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插件。