Comment détecter un changement dans une zone de texte?

J'ai actuellement lié mon espace de texte à quelques événements qui semblent fonctionner. Cependant, le problème est que les événements se chevauchent et déclenchent plusieurs fois, ce qui réduit les performances par trop.

Ce que je veux faire, c'est à peu près saisir toute modification de la zone de texte: cliquer, coller, cloner, déplacer vers le bas, faire un clic droit sur le menu contextuel (clic droit, couper / supprimer / coller), glisser-déposer, etc. -browser et au moins jusqu'à IE8. Les événements doivent être déclenchés lorsque vous déplacez le caret dans la zone de texte à l'aide de touches de direction ou similaires (je manipule les modifications en fonction de la position du caret, entre autres).

Je ne peux pas utiliser de retards majeurs. Dès que vous faites quelque chose avec la zone de texte, les événements doivent déclencher et exécuter n'importe quel code que j'ai là immédiatement.

Je suis en train d'utiliser jquery pour lier l'événement, mais je vais bien avec une solution javascript pure tant qu'il fonctionne sur le navigateur et fait ce que je veux.

Voici le code que j'utilise actuellement:

var deadKeycodes = [16, 17, 18, 19, 20, 27, 33, 34, 35, 36, 38, 40, 44, //37 = left arrow and 39 = right arrow removed, it needs to trigger on those 45, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 144, 145]; $(original).bind('propertychange keyup keydown input click', function(e) { if (!Array.prototype.indexOf || deadKeycodes.indexOf(e.keyCode) == -1) { // prevent execution when pressing a 'dead' key //do stuff here } }); 

Merci d'avance. Si quelque chose n'est pas clair, demandez simplement et je le clarifierai pour vous 🙂

Je ne pense pas que vous pouvez vraiment "résoudre" le problème dans le sens de l'arrêt de plusieurs événements à partir du tir. Keyup et keydown sont vraiment des événements différents et se produisent à des moments différents. Si vous souhaitez répondre aux deux (ce que vous faites probablement, car la saisie et la saisie des clés modifieront à la fois la zone de texte), les deux événements doivent être inclus. Cependant, la plupart du temps, ils vont déclencher presque simultanément (et plusieurs fois de suite), ce qui, comme vous le signalez, peut poser un problème de performance.

Au lieu de cela, vous devriez probablement envisager de déclencher un rappel d' étranglement ou de rebond . Un renvoi limité ne déclenchera qu'une fois tous les n millisecondes (bon pour les fonctions qui pourraient être appelées trop). Un rappel de rappel ne se déclenchera qu'après l'exécution d'un flux d'événements; Après n millisecondes écoulées depuis le dernier rappel.

Vous pouvez facilement l'accomplir en utilisant les fonctions de rebondissement et d' accélération du trait de soulignement.

Quelque chose comme:

 debouncedFn = _.debounce(function(e) { if (!Array.prototype.indexOf || deadKeycodes.indexOf(e.keyCode) == -1) { // prevent execution when pressing a 'dead' key //do stuff here } }, 100); $(original).bind('propertychange keyup keydown input click', debouncedFn); 

Votre original est une overkill. Tout ce dont vous avez besoin sont les événements d' input et d' input propertychange .

Mise à jour 2016

La page initialement liée a disparu. Voici un instantané légèrement sous-optimisé:

http://web.archive.org/web/20140810185102/http://whattheheasaid.com/2010/09/effectively-detecting-user-input-in-javascript

Voici une réponse démontrant l'utilisation de l'événement d' input et la baisse de l'échange de propertychange dans IE <= 8:

Ne capturez que les touches qui changent d'entrée?

Pour éviter que l'événement ne se chevauche, vous pouvez enregistrer l'heure du dernier appel. Avant d'exécuter le rappel d'un événement, vous testez si un temps suffisant a réussi à déclencher.

 $(original).bind('propertychange keyup keydown input click', (function () { var lastCallTime = 0; return function (e) { if (Date.now() - lastCallTime < 50) { return; } // Too little time has passed--exit if (!Array.prototype.indexOf || deadKeycodes.indexOf(e.keyCode) == -1) { lastCallTime = Date.now(); // your code... } }; }())); 

Cela semble le résoudre dans IE7-9 et Chrome, n'ont pas testé le reste. Un seul console.log se produit par changement indépendamment de la modification. S'il n'y avait pas de modifications, rien n'est enregistré: http://jsfiddle.net/SJN6J/2/

 var timer; $("textarea").on("keydown paste cut", function(){ clearTimeout(timer); var origvalue = this.value, self = this; timer = setTimeout(function(){ if ( origvalue !== self.value ) { console.log("it changed!"); // do stuff because content changed } },0); }); 

Remarque: mon test IE7-8 était avec IE9 changeant le mode navigateur, donc vous voudrez peut-être faire de vrais tests IE7-8.