У меня есть поле поиска. Сейчас он ищет каждую клавиатуру. Поэтому, если кто-то наберет "Windows", он выполнит поиск с AJAX для каждой клавиатуры: "W", "Wi", "Win", "Wind", "Windo", "Window", "Windows".
Я хочу иметь задержку, поэтому он выполняет поиск только тогда, когда пользователь перестает печатать на 200 мс.
В функции keyup
нет опции, и я пробовал setTimeout
, но он не работал.
Как я могу это сделать?
Я использую эту маленькую функцию для той же цели, выполняя функцию после того, как пользователь прекратил печатать в течение определенного периода времени или в событиях, которые запускаются с высокой скоростью, таких как 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
).
Для чего-то более сложного, посмотрите на плагин jQuery Typewatch.
Если вы хотите выполнить поиск после завершения типа, используйте глобальную переменную, чтобы удерживать тайм-аут, возвращенный с вашего вызова 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);
}
Еще одно небольшое улучшение в ответе 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);});
Вы также можете посмотреть underscore.js, который предоставляет полезные методы, такие как debounce:
var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);
Основываясь на ответе 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);
И просто используйте вот так:
$('#input').delayKeyup(function(){ alert("5 secondes passed from the last event keyup."); }, 5000);
Осторожно: переменная $(this) в функции, переданной как параметр, не соответствует вводу
Задержка многофункциональных вызовов с использованием меток
Это решение, с которым я работаю. Это задержит выполнение ЛЮБОЙ функции, которую вы хотите. Это может быть поисковый запрос по нажатию клавиши, может быть быстрый щелчок по предыдущей или следующей кнопке (в противном случае отправка множественного запроса будет выполняться при быстром щелчке и не будет использоваться в конце концов). При этом используется глобальный объект, который сохраняет каждое время выполнения и сравнивает его с самым последним запросом.
Таким образом, в результате будет вызван только последний щелчок/действие, поскольку эти запросы хранятся в очереди, то есть после вызова 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);
}
Вы можете установить собственное время задержки (необязательно, по умолчанию 500 мс). И отправьте аргументы вашей функции в "режиме закрытия".
Например, если вы хотите вызвать нижеуказанную функцию:
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);});
Приводит к вызову одной и той же функции, но задерживает их независимо, потому что их метки отличаются
Это сработало для меня, когда я задерживаю операцию поиска и делаю проверку, если значение такое же, как указано в текстовом поле. Если значение такое же, тогда я иду вперед и выполняю операцию для данных, относящихся к значению поиска.
$('#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);
});
Эта функция немного расширяет функцию ответа 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);
Я удивлен, что никто не упоминает проблему с несколькими входами в CMS очень красиво отрезанным.
В принципе, вам нужно будет определять переменную задержки отдельно для каждого входа. В противном случае, если sb помещает текст в первый вход и быстро переходит на другой вход и начинает печатать, обратный вызов для первого WILL NOT будет вызван!
См. код ниже. Я пришел с учетом других ответов:
(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.
Если кому-то нравится откладывать одну и ту же функцию и без внешней переменной, он может использовать следующий 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);
}
Функция задержки для вызова каждой клавиши. 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);
});
Супер простой подход, предназначенный для запуска функции после того, как пользователь закончил печатать в текстовом поле...
<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>
Сочетание ответа CMS с Miguel one дает надежное решение, допускающее одновременные задержки.
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');
});
Основываясь на ответе 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, но решает несколько ключевых вопросов для меня:
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
.Решение, которое я использую, добавляет еще один уровень сложности, что позволяет отменить выполнение, например, но это хорошая основа для построения.
Используйте
mytimeout = setTimeout( expression, timeout );
где выражение - это script для запуска, а время ожидания - это время ожидания в миллисекундах перед его запуском - это НЕ ХАРАКТЕРИСТИРОВАТЬ script, а просто задерживает выполнение этой части до истечения таймаута.
clearTimeout(mytimeout);
будет reset/очистить таймаут, чтобы он не запускал выражение script в выражении (например, отмена), если оно еще не выполнено.
Вот предложение, которое я написал, который заботится о нескольких вводах в вашей форме.
Эта функция получает объект поля ввода, помещает в ваш код
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);
});
var globalTimeout = null;
$('#search').keyup(function(){
if(globalTimeout != null) clearTimeout(globalTimeout);
globalTimeout =setTimeout(SearchFunc,200);
});
function SearchFunc(){
globalTimeout = null;
console.log('Search: '+$('#search').val());
//ajax code
};
Используйте bindWithDelay плагин jQuery:
element.bindWithDelay(eventType, [ eventData ], handler(eventObject), timeout, throttle)
Пользовательская библиотека lodash javascript и использование функции _.debounce
changeName: _.debounce(function (val) {
console.log(val)
}, 1000)
С ES6 можно также использовать синтаксис функции стрелки.
В этом примере код задерживает keyup
события для 400мса после того как пользователь закончить typeing перед вызовом 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);
})
Видел это сегодня немного поздно, но просто хочу поставить это здесь, если кому-то еще понадобится. просто отделите функцию, чтобы сделать ее многоразовой. код ниже будет ждать полтора секунды после остановки печати.
var timeOutVar
$(selector).on('keyup', function() {
clearTimeout(timeOutVar);
timeOutVar= setTimeout(function(){ console.log("Hello"); }, 500);
});
Ну, я также сделал фрагмент кода для ограничения высокочастотного запроса ajax-запроса Keyup/Keydown. Проверьте это:
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 */ });
});
Взгляните на плагин autocomplete. Я знаю, что он позволяет указать задержку или минимальное количество символов. Даже если вы не используете плагин, просмотр кода даст вам некоторые идеи о том, как его реализовать самостоятельно.