Obtener la posición del cursor (en caracteres) dentro de un campo de entrada de texto

212

¿Cómo puedo obtener la posición de intercalación desde un campo de entrada?

He encontrado algunos fragmentos a través de Google, pero nada a prueba de balas.

Básicamente, algo como un complemento jQuery sería ideal, por lo que podría simplemente hacer

$("#myinput").caretPosition()
MarkB29
fuente
2
Intente buscar 'posición del cursor', que le dará muchos más resultados, así como algunos temas sobre esto en SO.
Alec
2
@CMS Encontrar la posición en un <input>es mucho más simple que hacerlo en un <textarea>.
Andrew Mao
1
@AndrewMao: y mucho más difícil si el texto se desplaza y el cursor es sizecaracteres anteriores .
Dan Dascalescu
@alec: Estoy de acuerdo en que buscar el cursor en lugar del cursor puede producir más resultados. Como se señaló en otra parte, aprendí que caret es el término más apropiado. Un cursor representa una ubicación en cualquier cosa, mientras que un cursor representa una ubicación específicamente en el texto.
Suncat2000

Respuestas:

247

Actualización más fácil:

Use el field.selectionStart ejemplo en esta respuesta .

Gracias a @commonSenseCode por señalar esto.


Vieja respuesta:

Encontré esta solución. No está basado en jquery, pero no hay ningún problema para integrarlo en 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
fuente
9
else if (oField.selectionStart || oField.selectionStart == '0')podría serelse if (typeof oField.selectionStart==='number')
user2428118
¿Cuál es la idea de "oField.focus ()"? A mí me funciona sin esta línea. Tenga cuidado si usa el evento de desenfoque en su entrada y ejecuta esa función dentro de una devolución de llamada.
Kirill Reznikov
¿Estás probando eso en IE? Ese conjunto si la sección se ejecuta solo en IE. En IE solo hay una selección global, por eso es document.selection, no field.selectiono algo así. Además, fue posible en IE 7 (no sé si todavía es posible en 8+) seleccionar algo, y luego TAB fuera del campo sin perder la selección. De esta manera, cuando se selecciona el texto pero el campo no está enfocado, document.selectiondevuelve la selección cero. Es por eso que, como solución para este error, debe centrarse en el elemento antes de leer el document.selection.
bezmax
siempre obteniendo 0 para Chrome y
Firefox
117

Buena, muchas gracias a Max.

He incluido la funcionalidad de su respuesta en jQuery si alguien quiere usarla.

(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
fuente
3
¿No es lo input = $(this).get(0)mismo que input = this?
Mic
44
@Mic no, no en un complemento jQuery. En un complemento se thisrefiere a un conjunto completo envuelto. Sin embargo, su código sigue siendo incorrecto, debería serlo this.get(0). Su código probablemente todavía funcionó porque volver a envolver un conjunto envuelto no hace nada.
Chev
1
Esto me da información incorrecta. Estaba mirando las posiciones del cursor cuando entretenía el texto. Mi violín que demuestra esto es: jsfiddle.net/fallenreaper/TSwyk
Fallenreaper
1
Firefox genera un NS_ERROR_FAILURE en input.selectionStart cuando la entrada es de tipo numérico, ¿la envuelve en un intento {} catch {}?
niall.campbell
sería bueno para las nuevas abejas si agrega el uso de la función
Muhammad Omer Aslam
101

MUY FÁCIL

Respuesta actualizada

Uso selectionStart, es compatible con todos los principales navegadores .

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

Actualización: esto funciona solo cuando no se define ningún tipo o type="text"en la entrada.

CommonSenseCode
fuente
2
Si cambio de posición con el mouse, no se imprime en la consola. ¿Hay alguna forma de arreglarlo?
Eugene Barsky
3
@EugeneBarsky Simplemente agregue un nuevo detector de eventos para el evento de clic. Puede verificar la .selectionStartpropiedad en cualquier momento ( document.getElementById('foobar').selectionStart), no tiene que estar dentro de un detector de eventos.
JJJ
3
impresionante, pero no funciona en Firefox o Chrome cuando el tipo de entrada es número.
Adam R. Gray
26

Tengo una solución muy simple . Pruebe el siguiente código con resultado verificado :

<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>

Te estoy dando el violín

Rajesh Paul
fuente
13
slicees una operación relativamente costosa y no agrega nada a esta 'solución': el.selectionStartes equivalente a la longitud de su segmento; solo devuélvelo. Además, la razón por la que las otras soluciones son más complicadas es porque tratan con otros navegadores que no son compatibles selectionStart.
mpen
Dejé los trabajos donde tenía que trabajar con código con nombres de variables como este.
Michael Scheper
@Michael Scheper - ¿Te refieres a 'el' para elemento y 'val' para valor? Esos son bastante comunes ...
user2782001
66
@ user2782001: Hablé mal, mi principal preocupación era el nombre de la función. f1es tan significativo como 'user2782001'. 😉
Michael Scheper
16

Ahora hay un buen complemento para esto: el complemento Caret

Luego puede obtener la posición usando $("#myTextBox").caret()o establecerla a través de$("#myTextBox").caret(position)

Jens Mikkelsen
fuente
1
el plugin caret parece ser para elementos de área de texto, no entradas
schmidlop
44
Bueno, lo tengo funcionando para <input type = "text" id = "myTextBox" /> y uso el código anterior.
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);
Jorge
fuente
10

Hay algunas buenas respuestas publicadas aquí, pero creo que puede simplificar su código y omitir la verificación de inputElement.selectionStartsoporte: no solo es compatible con IE8 y versiones anteriores (consulte la documentación ) que representa menos del 1% del uso actual del navegador .

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
fuente
2

Quizás necesite un rango seleccionado además de la posición del cursor. Aquí hay una función simple, ni siquiera necesita 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)');
    }
}

Digamos que quiere llamarlo en una entrada cada vez que cambia o el mouse mueve la posición del cursor (en este caso estamos usando jQuery .on()). Por razones de rendimiento, puede ser una buena idea agregar setTimeout()o algo así como guiones bajos _debounce()si los eventos están llegando:

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

Aquí hay un violín si quieres probarlo: https://jsfiddle.net/Dhaupin/91189tq7/

dhaupin
fuente
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
fuente