Obtenir la position du curseur (en caractères) dans un champ de saisie de texte

212

Comment obtenir la position du curseur dans un champ de saisie?

J'ai trouvé quelques morceaux via Google, mais rien de pare-balles.

Fondamentalement, quelque chose comme un plugin jQuery serait idéal, donc je pourrais simplement faire

$("#myinput").caretPosition()
MarkB29
la source
2
Essayez de rechercher la «position du curseur», qui vous donnera beaucoup plus de visites, ainsi que quelques sujets à ce sujet sur SO.
Alec
2
@CMS Trouver la position dans un <input>est beaucoup plus simple que de le faire dans un <textarea>.
Andrew Mao
1
@AndrewMao: et bien plus difficile si le texte défile et que le curseur est passé de sizecaractères.
Dan Dascalescu
@alec: je suis d'accord que la recherche du curseur au lieu du curseur peut donner plus de résultats. Comme indiqué ailleurs, j'ai appris que caret est le terme le plus approprié. Un curseur représente un emplacement dans quoi que ce soit alors qu'un caret représente un emplacement spécifique dans le texte.
Suncat2000

Réponses:

247

Mise à jour plus simple:

Utilisez l' field.selectionStart exemple dans cette réponse .

Merci à @commonSenseCode de l'avoir signalé.


Ancienne réponse:

J'ai trouvé cette solution. Pas basé sur jquery mais il n'y a aucun problème à l'intégrer à jquery:

/*
** Returns the caret (cursor) position of the specified text field (oField).
** Return value range is 0-oField.value.length.
*/
function doGetCaretPosition (oField) {

  // Initialize
  var iCaretPos = 0;

  // IE Support
  if (document.selection) {

    // Set focus on the element
    oField.focus();

    // To get cursor position, get empty selection range
    var oSel = document.selection.createRange();

    // Move selection start to 0 position
    oSel.moveStart('character', -oField.value.length);

    // The caret position is selection length
    iCaretPos = oSel.text.length;
  }

  // Firefox support
  else if (oField.selectionStart || oField.selectionStart == '0')
    iCaretPos = oField.selectionDirection=='backward' ? oField.selectionStart : oField.selectionEnd;

  // Return results
  return iCaretPos;
}
bezmax
la source
9
else if (oField.selectionStart || oField.selectionStart == '0')pourrait êtreelse if (typeof oField.selectionStart==='number')
user2428118
Quelle est l'idée de "oField.focus ()"? Cela fonctionne pour moi sans cette ligne. Soyez prudent si vous utilisez un événement flou sur votre entrée et exécutez cette fonction dans un rappel.
Kirill Reznikov,
Testez-vous cela sur IE? Tout cela si la section est exécutée uniquement sur IE. Dans IE, il n'y a qu'une sélection globale, c'est pourquoi c'est document.selection, pas field.selectionou quelque chose. En outre, il était possible dans IE 7 (je ne sais pas s'il est toujours possible dans 8+) de sélectionner quelque chose, puis de TAB hors du champ sans perdre la sélection. De cette façon, lorsque le texte est sélectionné mais que le champ n'est pas focalisé, document.selectionretourne une sélection nulle. C'est pourquoi, comme solution de contournement pour ce bogue, vous devez vous concentrer sur l'élément avant de lire le document.selection.
bezmax
toujours obtenir 0 pour chrome et firefox
Kaushik Thanki
117

Sympa, grand merci à Max.

J'ai encapsulé la fonctionnalité dans sa réponse dans jQuery si quelqu'un veut l'utiliser.

(function($) {
    $.fn.getCursorPosition = function() {
        var input = this.get(0);
        if (!input) return; // No (input) element found
        if ('selectionStart' in input) {
            // Standard-compliant browsers
            return input.selectionStart;
        } else if (document.selection) {
            // IE
            input.focus();
            var sel = document.selection.createRange();
            var selLen = document.selection.createRange().text.length;
            sel.moveStart('character', -input.value.length);
            return sel.text.length - selLen;
        }
    }
})(jQuery);
MarkB29
la source
3
N'est-ce pas input = $(this).get(0)la même chose que input = this?
Mic
4
@Mic non, pas dans un plugin jQuery. Dans un plugin se thisréfère à un ensemble complet enveloppé. Son code est toujours faux cependant, il devrait l'être this.get(0). Son code fonctionnait probablement encore car le ré-emballage d'un ensemble encapsulé ne fait rien.
Chev
1
Cela me donne de fausses informations. Je regardais les positions des curseurs lors de la lecture de texte. Mon violon démontrant ceci est: jsfiddle.net/fallenreaper/TSwyk
Fallenreaper
1
Firefox génère un NS_ERROR_FAILURE sur input.selectionStart lorsque l'entrée est de type numérique, enveloppez-la dans un essai {} catch {}?
niall.campbell
serait bien pour les nouvelles abeilles si vous ajoutez l'utilisation de la fonction
Muhammad Omer Aslam
101

TRÈS FACILE

Réponse mise à jour

Utilisation selectionStart, il est compatible avec tous les principaux navigateurs .

document.getElementById('foobar').addEventListener('keyup', e => {
  console.log('Caret at: ', e.target.selectionStart)
})
<input id="foobar" />

Mise à jour: cela ne fonctionne que si aucun type n'est défini ou type="text"sur l'entrée.

CommonSenseCode
la source
2
Si je change de position à l'aide de la souris, elle n'est pas imprimée dans la console. Y a-t-il un moyen de le réparer?
Eugene Barsky
3
@EugeneBarsky Il suffit d'ajouter un nouvel écouteur d'événement pour l'événement click. Vous pouvez vérifier la .selectionStartpropriété à tout moment ( document.getElementById('foobar').selectionStart), elle ne doit pas nécessairement se trouver dans un écouteur d'événements.
JJJ
3
génial, mais ne fonctionne pas dans Firefox ou Chrome lorsque le type d'entrée est nombre.
Adam R. Gray
26

Vous avez une solution très simple . Essayez le code suivant avec un résultat vérifié -

<html>
<head>
<script>
    function f1(el) {
    var val = el.value;
    alert(val.slice(0, el.selectionStart).length);
}
</script>
</head>
<body>
<input type=text id=t1 value=abcd>
    <button onclick="f1(document.getElementById('t1'))">check position</button>
</body>
</html>

Je te donne le fiddle_demo

Rajesh Paul
la source
13
sliceest une opération relativement coûteuse et n'ajoute rien à cette «solution» - el.selectionStartéquivaut à la longueur de votre tranche; il suffit de retourner cela. De plus, la raison pour laquelle les autres solutions sont plus compliquées est qu'elles traitent avec d'autres navigateurs qui ne prennent pas en charge selectionStart.
mpen
J'ai quitté des emplois où je devais travailler avec du code avec des noms de variables comme celui-ci.
Michael Scheper
@Michael Scheper - Vous voulez dire «el» pour l'élément et «val» pour la valeur? Ce sont assez courants ...
user2782001
6
@ user2782001: J'ai mal parlé - ma principale préoccupation était le nom de la fonction. f1est à peu près aussi significatif que «user2782001». 😉
Michael Scheper
16

Il existe maintenant un joli plugin pour cela: le plugin Caret

Ensuite, vous pouvez obtenir la position en utilisant $("#myTextBox").caret()ou la définir via$("#myTextBox").caret(position)

Jens Mikkelsen
la source
1
le plugin caret semble être pour les éléments textarea et non pour les entrées
schmidlop
4
Eh bien, je l'ai fait fonctionner pour <input type = "text" id = "myTextBox" /> et utiliser le code ci-dessus.
Jens Mikkelsen
14
   (function($) {
    $.fn.getCursorPosition = function() {
        var input = this.get(0);
        if (!input) return; // No (input) element found
        if (document.selection) {
            // IE
           input.focus();
        }
        return 'selectionStart' in input ? input.selectionStart:'' || Math.abs(document.selection.createRange().moveStart('character', -input.value.length));
     }
   })(jQuery);
George
la source
10

Il y a quelques bonnes réponses publiées ici, mais je pense que vous pouvez simplifier votre code et ignorer la vérification de la inputElement.selectionStartprise en charge: il n'est pas pris en charge uniquement sur IE8 et versions antérieures (voir la documentation ), ce qui représente moins de 1% de l' utilisation actuelle du navigateur .

var input = document.getElementById('myinput'); // or $('#myinput')[0]
var caretPos = input.selectionStart;

// and if you want to know if there is a selection or not inside your input:

if (input.selectionStart != input.selectionEnd)
{
    var selectionValue =
    input.value.substring(input.selectionStart, input.selectionEnd);
}
pmrotule
la source
2

Vous avez peut-être besoin d'une plage sélectionnée en plus de la position du curseur. Voici une fonction simple, vous n'avez même pas besoin de jQuery:

function caretPosition(input) {
    var start = input[0].selectionStart,
        end = input[0].selectionEnd,
        diff = end - start;

    if (start >= 0 && start == end) {
        // do cursor position actions, example:
        console.log('Cursor Position: ' + start);
    } else if (start >= 0) {
        // do ranged select actions, example:
        console.log('Cursor Position: ' + start + ' to ' + end + ' (' + diff + ' selected chars)');
    }
}

Disons que vous voulez l'appeler sur une entrée chaque fois qu'elle change ou que la souris déplace la position du curseur (dans ce cas, nous utilisons jQuery .on()). Pour des raisons de performances, il peut être judicieux d'ajouter setTimeout()ou quelque chose comme Underscores _debounce()si les événements affluent:

$('input[type="text"]').on('keyup mouseup mouseleave', function() {
    caretPosition($(this));
});

Voici un violon si vous voulez l'essayer: https://jsfiddle.net/Dhaupin/91189tq7/

dhaupin
la source
0

const inpT = document.getElementById("text-box");
const inpC = document.getElementById("text-box-content");
// swch gets  inputs .
var swch;
// swch  if corsur is active in inputs defaulte is false .
var isSelect = false;

var crnselect;
// on focus
function setSwitch(e) {
  swch = e;
  isSelect = true;
  console.log("set Switch: " + isSelect);
}
// on click ev
function setEmoji() {
  if (isSelect) {
    console.log("emoji added :)");
    swch.value += ":)";
    swch.setSelectionRange(2,2 );
    isSelect = true;
  }

}
// on not selected on input . 
function onout() {
  // الافنت  اون كي اب 
  crnselect = inpC.selectionStart;
  
  // return input select not active after 200 ms .
  var len = swch.value.length;
  setTimeout(() => {
   (len == swch.value.length)? isSelect = false:isSelect = true;
  }, 200);
}
<h1> Try it !</h1>
    
		<input type="text" onfocus = "setSwitch(this)" onfocusout = "onout()" id="text-box" size="20" value="title">
		<input type="text" onfocus = "setSwitch(this)"  onfocusout = "onout()"  id="text-box-content" size="20" value="content">
<button onclick="setEmoji()">emogi :) </button>

Omar bakhsh
la source