J'ai un champ de recherche. En ce moment, il cherche chaque keyup. Donc si quelqu'un tape “Windows”, il fera une recherche avec AJAX pour chaque keyup: “W”, “Wi”, “Win”, “Wind”, “Windo”, “Window”, “Windows” .
Je souhaite un délai, de sorte qu'il recherche uniquement lorsque l'utilisateur cesse de taper pendant 200 ms.
Il n’existe pas d’option pour cela dans la fonction keyup
et j’ai essayé setTimeout
, mais cela n’a pas fonctionné.
Comment puis je faire ça?
J'utilise cette petite fonction dans le même but, en l'exécutant une fois que l'utilisateur a cessé de taper pendant un laps de temps spécifié ou dans des événements qui se déclenchent à une vitesse élevée, comme 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>
La fonction delay
renverra une fonction encapsulée qui gère en interne un temporisateur individuel. Lors de chaque exécution, le temporisateur est redémarré avec le délai imparti. Si plusieurs exécutions ont lieu avant ce délai, le temporisateur se réinitialise et redémarre.
Lorsque le temporisateur se termine enfin, la fonction de rappel est exécutée en transmettant le contexte et les arguments d'origine (dans cet exemple, l'objet événement de jQuery et l'élément DOM sous la forme this
).
Pour quelque chose de plus sophistiqué, jetez un coup d’œil au plugin jQuery Typewatch .
Si vous souhaitez effectuer une recherche une fois le type défini, utilisez une variable globale pour conserver le délai d'attente renvoyé par votre appel setTimout
et annulez-le avec une variable clearTimeout
s'il n'a pas encore eu lieu, de sorte qu'il ne déclenche pas le délai d'expiration sauf le dernier paramètre keyup
. un événement
var globalTimeout = null;
$('#id').keyup(function(){
if(globalTimeout != null) clearTimeout(globalTimeout);
globalTimeout =setTimeout(SearchFunc,200);
}
function SearchFunc(){
globalTimeout = null;
//ajax code
}
Ou avec une fonction anonyme:
var globalTimeout = null;
$('#id').keyup(function() {
if (globalTimeout != null) {
clearTimeout(globalTimeout);
}
globalTimeout = setTimeout(function() {
globalTimeout = null;
//ajax code
}, 200);
}
Une autre légère amélioration sur la réponse de CMS. Pour permettre facilement des délais distincts, vous pouvez utiliser les éléments suivants:
function makeDelay(ms) {
var timer = 0;
return function(callback){
clearTimeout (timer);
timer = setTimeout(callback, ms);
};
};
Si vous voulez réutiliser le même délai, faites juste
var delay = makeDelay(250);
$(selector1).on('keyup', function() {delay(someCallback);});
$(selector2).on('keyup', function() {delay(someCallback);});
Si vous voulez des délais séparés, vous pouvez faire
$(selector1).on('keyup', function() {makeDelay(250)(someCallback);});
$(selector2).on('keyup', function() {makeDelay(250)(someCallback);});
Vous pouvez également consulter underscore.js , qui fournit des méthodes utilitaires telles que debounce :
var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);
Basé sur la réponse de CMS, j'ai fait ceci:
Mettez le code ci-dessous après inclure 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);
Et utilisez simplement comme ceci:
$('#input').delayKeyup(function(){ alert("5 secondes passed from the last event keyup."); }, 5000);
Attention: la variable $ (this) de la fonction passée en paramètre ne correspond pas à l'entrée
Cette fonction étend un peu la fonction de la réponse de Gaten afin de récupérer l'élément:
$.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);
Cela a fonctionné pour moi où j'ai retardé l'opération de logique de recherche et vérifié si la valeur est identique à celle entrée dans le champ de texte. Si la valeur est identique, j'effectue l'opération pour les données liées à la valeur de recherche.
$('#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);
});
Si quelqu'un aime retarder la même fonction et sans variable externe, il peut utiliser le script suivant:
function MyFunction() {
//Delaying the function execute
if (this.timer) {
window.clearTimeout(this.timer);
}
this.timer = window.setTimeout(function() {
//Execute the function code here...
}, 500);
}
Je suis surpris que personne ne mentionne le problème de la saisie multiple dans le très joli CMS coupé par CMS.
En gros, vous devez définir une variable de délai individuellement pour chaque entrée. Sinon, si sb met du texte dans la première entrée et passe rapidement à une autre entrée et commence à taper, rappelle pour la première WON'T be call!
Voir le code ci-dessous je suis venu avec basé sur d'autres réponses:
(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);
Cette solution conserve la référence setTimeout dans la variable delayTimer de l'entrée. Il transmet également la référence de l'élément au rappel comme suggéré par fazzyx.
Testé dans IE6, 8 (comp - 7), 8 et Opera 12.11.
Retarder la fonction pour appeler sur chaque keyup . jQuery 1.7.1 ou supérieur requis
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 );
});
}
Usage: $('#searchBox').keyupDelay( cb );
Approche super simple, conçue pour exécuter une fonction après qu'un utilisateur a fini de taper dans un champ de texte ...
<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>
En se basant sur la réponse de CMS, voici une nouvelle méthode de délai qui préserve "ceci" dans son utilisation:
var delay = (function(){
var timer = 0;
return function(callback, ms, that){
clearTimeout (timer);
timer = setTimeout(callback.bind(that), ms);
};
})();
Usage:
$('input').keyup(function() {
delay(function(){
alert('Time elapsed!');
}, 1000, this);
});
C’est une solution qui ressemble au système de gestion de contenu, mais résout quelques problèmes clés pour moi:
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)
}
}
}
}())
Usage:
signup.key.addEventListener('keyup', function() {
delay(this).enqueue(300, function() {
console.log(this.value)
})
})
Le code est écrit dans un style qui me convient, il se peut que vous deviez ajouter un groupe de points-virgules.
Points à garder à l'esprit:
this
fonctionne comme prévu (comme dans l'exemple).setTimeout
.La solution que j'utilise ajoute un autre niveau de complexité, vous permettant par exemple d’annuler l’exécution, mais c’est une bonne base de travail.
En combinant la réponse CMS avec celle de Miguel , vous obtenez une solution robuste permettant des retards simultanés.
var delay = (function(){
var timers = {};
return function (callback, ms, label) {
label = label || 'defaultTimer';
clearTimeout(timers[label] || 0);
timers[label] = setTimeout(callback, ms);
};
})();
Lorsque vous devez retarder différentes actions indépendamment, utilisez le troisième argument.
$('input.group1').keyup(function() {
delay(function(){
alert('Time elapsed!');
}, 1000, 'firstAction');
});
$('input.group2').keyup(function() {
delay(function(){
alert('Time elapsed!');
}, 1000, '2ndAction');
});
Basé sur la réponse du CMS, il ignore simplement les événements clés qui ne changent pas de valeur.
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 );
})
Utilisation
mytimeout = setTimeout( expression, timeout );
où expression est le script à exécuter et timeout, le délai d'attente, en millisecondes, avant de s'exécuter - cela ne perturbe PAS le script, mais retarde simplement l'exécution de cette partie jusqu'à la fin du délai.
clearTimeout(mytimeout);
réinitialisera/effacera le délai afin de ne pas exécuter le script dans une expression (comme une annulation) tant qu'il n'a pas encore été exécuté.
Utilisez le plugin bindWithDelay jQuery:
element.bindWithDelay(eventType, [ eventData ], handler(eventObject), timeout, throttle)
Voici une suggestion que j'ai écrite et qui prend en charge plusieurs entrées dans votre formulaire.
Cette fonction récupère l'objet du champ de saisie, mis dans votre code
function fieldKeyup(obj){
// what you want this to do
} // fieldKeyup
C'est la fonction delayCall réelle, prend en charge plusieurs champs de saisie
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
Usage:
$("#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
};
Eh bien, j'ai également fait un morceau de code pour limiter cause haute demande ajax par Keyup/Keydown. Regarde ça:
https://github.com/raincious/jQueue
Faites votre requête comme ceci:
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.
Et lier un événement comme ceci:
$('#field-username').keyup(function() {
q.run('Username', this.val(), function() { /* calling back */ });
});
Bibliothèque utilisateur lodash javascript et utilisation de la fonction _.debounce
changeName: _.debounce(function (val) {
console.log(val)
}, 1000)
Nous avons vu cela aujourd'hui un peu tard, mais je voulais simplement mettre ceci ici au cas où quelqu'un d'autre en aurait besoin. séparez simplement la fonction pour la rendre réutilisable. le code ci-dessous attendra 1/2 seconde après avoir tapé stop.
var timeOutVar
$(selector).on('keyup', function() {
clearTimeout(timeOutVar);
timeOutVar= setTimeout(function(){ console.log("Hello"); }, 500);
});
Jetez un coup d'œil au autocomplete plugin. Je sais que cela vous permet de spécifier un délai ou un nombre minimum de caractères. Même si vous n'utilisez pas le plugin, parcourir le code vous donnera quelques idées pour l'implémenter vous-même.
A partir de ES6, vous pouvez utiliser la syntaxe de la fonction de flèche .
Dans cet exemple, le code retarde l'événement keyup
pendant 400 ms après que les utilisateurs aient fini de taper avant d'appeler searchFunc
de faire une demande de requête.
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);
})