web-dev-qa-db-fra.com

Comment détecter si la touche enfoncée produira un caractère à l'intérieur d'une zone de texte <input>?

J'ai une zone de texte régulière:

<input type="text"> 

J'utilise jQuery pour gérer les événements liés aux clés:

$("input:text").keydown(function() {
    // keydown code
}).keypress(function() {
    // keypress code
}).keyup(function() {
    // keyup code
});

L'utilisateur se concentre sur une zone de texte et appuie sur différentes touches de son clavier (les habituelles: lettres, chiffres, MAJ, RETOUR ARRIÈRE, ESPACE, ...). J'ai besoin de détecter quand l'utilisateur appuie sur une touche qui va augmenter la longueur de la valeur de la zone de texte. Par exemple, la touche "A" l'augmentera, la touche "SHIFT" ne le fera pas.

Je me souviens avoir regardé une conférence de PPK où il a mentionné la différence entre ces deux. Cela a quelque chose à voir avec l'événement - keydown vs keypress - et éventuellement avec les propriétés de l'événement - key, char, keyCode.

Mettre à jour !

J'ai besoin de connaître ces informations dans les gestionnaires de touches ou de touches. Je ne peux pas attendre que l'événement keyup se produise.

Pourquoi j'en ai besoin:

J'ai une zone de texte dont la taille change dynamiquement en fonction de l'entrée utilisateur. Vous pouvez jeter un œil à cette démo: http://vidasp.net/tinydemos/variable-size-text-box.html

Dans la démo, j'ai un gestionnaire de keydown et de keyup. Le gestionnaire de touches ajuste la taille de la zone de texte en fonction de la valeur d'entrée. Cependant, le gestionnaire de keydown définit la taille à 1 caractère de plus que la valeur d'entrée. La raison pour laquelle je fais cela est que si je ne le faisais pas, alors le caractère déborderait en dehors de la zone de texte et seulement lorsque l'utilisateur relâcherait la clé, la zone de texte se développerait. Ça a l'air bizarre. C'est pourquoi je dois anticiper le nouveau caractère - j'agrandis la zone de texte sur chaque touche, ergo, avant que le caractère n'apparaisse dans la zone de texte. Comme vous pouvez le voir dans la démo, cette méthode a fière allure.

Cependant, le problème provient des touches RETOUR ARRIÈRE et FLÈCHE - elles développeront également la zone de texte lors de la frappe, et uniquement lors de la frappe, la taille de la zone de texte sera corrigée.

Une solution de contournement:

Une solution de contournement serait de détecter manuellement les touches RETOUR ARRIÈRE, MAJ et FLÈCHE et d'agir en fonction de cela:

// keydown handler
function(e) {
    var len = $(this).val().length;
    if (e.keyCode === 37 || e.keyCode === 39 ||
        e.keyCode === 16) { // ARROW LEFT or ARROW RIGHT or SHIFT key
        return;
    } else if (e.keyCode === 8) { // BACKSPACE key
        $(this).attr("size", len <= 1 ? 1 : len - 1);
    } else {
        $(this).attr("size", len === 0 ? 1 : len + 1);
    }
}

Cela fonctionne (et a fière allure) pour RETOUR ARRIÈRE, MAJ, FLÈCHE GAUCHE et FLÈCHE DROITE. Cependant, j'aimerais avoir une solution plus robuste.

35
Šime Vidas

Je pense que cela fera le travail, ou sinon il est très proche et ne nécessitera que des ajustements mineurs. La chose dont vous devez vous souvenir est que vous ne pouvez rien dire de manière fiable sur un caractère pouvant être tapé dans un événement keydown ou keyup: tout doit être fait dans un keypress gestionnaire. La ressource définitive pour les événements clés est http://unixpapa.com/js/key.html

Vous devez également prendre en compte les pâtes, que ce code ne gère pas. Vous aurez besoin d'avoir un gestionnaire d'événements paste distinct (bien que cet événement ne soit pas pris en charge dans Firefox <3.0, Opera et les très anciens navigateurs WebKit). Vous aurez besoin d'une minuterie dans votre gestionnaire de collage car il est impossible en JavaScript d'accéder au contenu qui est sur le point d'être collé.

function isCharacterKeyPress(evt) {
    if (typeof evt.which == "undefined") {
        // This is IE, which only fires keypress events for printable keys
        return true;
    } else if (typeof evt.which == "number" && evt.which > 0) {
        // In other browsers except old versions of WebKit, evt.which is
        // only greater than zero if the keypress is a printable key.
        // We need to filter out backspace and ctrl/alt/meta key combinations
        return !evt.ctrlKey && !evt.metaKey && !evt.altKey && evt.which != 8;
    }
    return false;
}

<input type="text" onkeypress="alert(isCharacterKeyPress(event))">
29
Tim Down

Voici une solution beaucoup plus simple qui a bien fonctionné pour moi:

document.addEventListener('keyup', event => {
  if (String.fromCharCode(event.keyCode).match(/(\w|\s)/g)) {
    //pressed key is a char
  } else {
    //pressed key is a non-char
    //e.g. 'esc', 'backspace', 'up arrow'
  }
});

Cela ne nécessite pas de sonder un élément DOM (ce qui ajouterait de la latence et de la laideur).

Exemple d'utilisation mise à jour:

11
mike-shtil

La solution possible que je peux trouver est de vérifier la longueur de la clé dans l'événement.

Par exemple:-

<input type="text" id="testId" onkeyup="keyChecking(event)" />

<script type="text/javascript">
function keyChecking(event) {

    if (event.key.length == 1) {
        alert("key produced character " + event.key);
    } else {
        alert("Key DOES NOT produce character");

        const alphabets = "AZaz09";
        const key = event.key;
        var notEvenASymbol = false;

        for (let i = 0; i < key.length; i++) {
            var charCode = key.charCodeAt(i);
            if ((charCode >= alphabets.charCodeAt(0) && charCode <= alphabets.charCodeAt(1)) ||
                (charCode >= alphabets.charCodeAt(2) && charCode <= alphabets.charCodeAt(3)) ||
                (charCode >= alphabets.charCodeAt(4) && charCode <= alphabets.charCodeAt(5))
            ) {
                notEvenASymbol = true;
                console.log(charCode);
                break;
            }
        }

        if (notEvenASymbol) {
            alert("Key DOES NOT produce even a symbol");
        }
        console.log(event.key);

    }
}    
</script>

Donc, si vous appuyez sur des caractères/symboles, le event.key contiendra ce caractère et sa longueur sera 1. Si vous appuyez sur caractère [~ # ~] v [~ # ~] , puis le event.key aura une valeur [~ # ~] v [~ # ~] mais si vous appuyez sur la touche Entrée, il contiendra de la valeur Entrez , si vous appuyez sur shift puis Shift et ainsi de suite. Par conséquent, si une clé ne produit pas de caractère, sa longueur sera supérieure à 1.

mis à jour

Certaines touches spéciales du clavier produisent un symbole et sa longueur peut être supérieure à 1, j'ai donc modifié le code pour qu'il puisse alerter même s'il ne s'agit pas d'un symbole. Par exemple:- ???? sa longueur est de 2. Certains claviers mobiles ont des touches de raccourci pour ces symboles.

Une touche non caractère/symbole du clavier sera toujours une combinaison d'alphabets, de chiffres ou des deux, par exemple: - F2 , Maj .

Merci à @Vicky Chijwani d'avoir attiré l'attention sur ce scénario.

9
Visruth

OK, je pense que je l'ai. La solution est un peu hackeuse, mais fonctionne vraiment très bien.

Lors du keydown, effectuez un setTimeout pendant 1 milliseconde, qui appelle une fonction pour vérifier/modifier la longueur de votre zone de saisie.

http://jsfiddle.net/rygar/e2wQM/

Cela semble très bien fonctionner, en particulier dans certains endroits où votre version ne fonctionne pas (par exemple, retour arrière, CTRL + V, ou sélectionner tout un tas de texte et appuyer sur Supprimer)

Edit: Même setTimeout avec un retard de 0 ms semble fonctionner!

4
Jeff

Vous devez utiliser la propriété keyEventArgs.Key dans la fonction keydown, cela renverra la valeur numérique qui dépendra du système.

voici un lien qui a les différents codes clés pour les différents navigateurs et OS:

http://www.quirksmode.org/js/keys.html

3
mariana soffer

Ce n'est peut-être pas la méthode que vous recherchez, mais vous pouvez simplement vérifier la valeur de this.value.length dans votre fonction keydown. La valeur de retour est la longueur du texte dans le champ de saisie AVANT d'ajouter le nouveau caractère. Donc, si vous vérifiez à nouveau la longueur dans la fonction de saisie, elle sera plus grande si l'utilisateur a appuyé sur un caractère, mais la même chose si l'utilisateur a appuyé sur la touche Maj.

1
Jeff

Je suppose que vous configurez un compteur sur la longueur d'un champ de saisie, auquel cas vous n'avez pas besoin d'être aussi sophistiqué, vous pouvez simplement continuer d'affecter la longueur du champ à une variable, et lorsque l'utilisateur accède à votre la longueur maximale ne leur permet que d'appuyer sur la suppression ou le retour arrière comme ceci:

$("input:text").keypress(function() {
var current = $(this).val().length;
if (current >= 130) {
if (e.which != 0 && e.which != 8) {
e.preventDefault();
}
}
}

Vous pouvez également utiliser la variable actuelle pour afficher le compteur, ou faire maxlength - current pour faire un compte à rebours du nombre de caractères restant

1
Liam Bailey

Votre objectif de garder la zone de texte plus grande que le texte qui y a été saisi.

J'accomplirais cela en prévoyant d'avoir de la place pour deux caractères supplémentaires (pas un) dans la zone de texte. Ensuite:

// pseudo-code.... 
old_len = textbox.value.length
keyUp function() {
  var new_len = textbox.value.length
  if (new_len != old_len) {
    old_len = new_len
    textbox.style.size = new_len + 2 // pseudo code.
  }
}

L'avantage de ce qui précède est que vous n'avez pas besoin de descendre dans le monde inférieur des codes clés.

1
Larry K