Obter posição do cursor (em caracteres) dentro de um campo de entrada de texto

211

Como posso obter a posição do cursor de dentro de um campo de entrada?

Encontrei alguns pedaços no Google, mas nada à prova de balas.

Basicamente, algo como um plugin jQuery seria ideal, então eu poderia simplesmente fazer

$("#myinput").caretPosition()
MarkB29
fonte
2
Tente pesquisar por 'posição do cursor', que lhe dará muito mais hits, além de alguns tópicos sobre isso no SO.
Alec
2
@CMS Encontrar a posição de uma <input>maneira é muito mais simples do que fazê-lo em uma <textarea>.
Andrew Mao
1
@ AndrewMao: e muito mais difícil se o texto for rolado e o sinal de intercalação tiver sizecaracteres passados .
Dan Dascalescu 22/03
@alec: Concordo que procurar por cursor em vez de sinal de intercalação pode render mais resultado. Como apontado em outro lugar, aprendi que o sinal de intercalação é o termo mais apropriado. Um cursor representa um local em qualquer coisa, enquanto um cursor mostra um local especificamente no texto.
Suncat2000

Respostas:

247

Atualização mais fácil:

Use o field.selectionStart exemplo nesta resposta .

Obrigado a @commonSenseCode por apontar isso.


Resposta antiga:

Encontrei esta solução. Não é baseado em jquery, mas não há problema em integrá-lo ao 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
fonte
9
else if (oField.selectionStart || oField.selectionStart == '0')pode serelse if (typeof oField.selectionStart==='number')
user2428118 18/10/2013
Qual é a idéia de "oField.focus ()"? Funciona para mim sem essa linha. Tenha cuidado se você usar um evento de desfoque em sua entrada e executar essa função dentro de um retorno de chamada.
Kirill Reznikov
Você está testando isso no IE? Toda essa seção se é executada apenas no IE. No IE, há apenas uma seleção global, é por isso que é document.selection, não field.selectionou algo assim. Além disso, no IE 7 foi possível (não sei se ainda é possível no 8+) selecionar algo e, em seguida, TAB fora do campo sem perder a seleção. Dessa forma, quando o texto é selecionado, mas o campo não está focado, document.selectionretorna a seleção zero. É por isso que, como solução alternativa para esse bug, você precisa se concentrar no elemento antes de ler o document.selection.
Bezmax
sempre recebendo 0 para Chrome e Firefox
Kaushik Thanki
117

Agradável, muito obrigado a Max.

Embrulhei a funcionalidade em sua resposta no jQuery, se alguém quiser usá-lo.

(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
fonte
3
Não é input = $(this).get(0)o mesmo que input = this?
Mic
4
@ Mic não, não em um plugin jQuery. Em um plug-in, thisrefere-se a um conjunto completo agrupado. Seu código ainda está errado, deveria ser apenas this.get(0). Seu código provavelmente ainda funcionou porque o novo agrupamento de um conjunto agrupado não faz nada.
Chev
1
Isso me dá informações erradas. Eu estava olhando as posições do cursor ao inserir texto. Meu violino demonstrando isto é: jsfiddle.net/fallenreaper/TSwyk
Fallenreaper
1
O Firefox gera um NS_ERROR_FAILURE em input.selectionStart quando a entrada é do tipo número, envolva-a em uma tentativa {} catch {}?
Niall.campbell
Seria bom para as novas abelhas se você adicionar o uso para a função
Muhammad Omer Aslam
98

MUITO FÁCIL

Resposta atualizada

Use selectionStart, é compatível com todos os principais navegadores .

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

Atualização: Funciona apenas quando nenhum tipo está definido ou type="text"na entrada.

CommonSenseCode
fonte
2
Se eu mudar de posição usando o mouse, ele não será impresso no console. Existe uma maneira de consertar isso?
Eugene Barsky
3
@EugeneBarsky Basta adicionar um novo ouvinte de evento para o evento click. Você pode verificar a .selectionStartpropriedade a qualquer momento ( document.getElementById('foobar').selectionStart), pois ela não precisa estar dentro de um ouvinte de evento.
JJJ
3
incrível, mas não funciona no Firefox ou Chrome quando o tipo de entrada é o número.
Adam R. Gray
26

Tem uma solução muito simples . Experimente o seguinte código com 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>

Estou te dando o fiddle_demo

Rajesh Paul
fonte
13
sliceé uma operação relativamente cara e não acrescenta nada a essa 'solução' - el.selectionStarté equivalente ao comprimento da sua fatia; apenas devolva isso. Além disso, a razão pela qual as outras soluções são mais complicadas é porque elas lidam com outros navegadores que não suportam selectionStart.
simples
Saí de trabalhos em que tive que trabalhar com código com nomes de variáveis ​​como este.
Michael Scheper
@ Michael Scheper - Você quer dizer 'el' para elemento e 'val' para valor? Isso é bastante comum ... #
2762001
6
@ user2782001: Eu falhei errado - minha principal preocupação era o nome da função. f1é tão significativo quanto 'user2782001'. 😉
Michael Scheper
16

Agora existe um bom plugin para isso: O Caret Plugin

Em seguida, você pode obter a posição usando $("#myTextBox").caret()ou configurá-la via$("#myTextBox").caret(position)

Jens Mikkelsen
fonte
1
o plugin acento circunflexo parece ser para elementos textarea não inputs
schmidlop
4
Bem, eu consegui trabalhar para <input type = "text" id = "myTextBox" /> e use o código acima.
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
fonte
10

Há algumas boas respostas postadas aqui, mas acho que você pode simplificar seu código e pular a verificação de inputElement.selectionStartsuporte: ele não é suportado apenas no IE8 e versões anteriores (consulte a documentação ), que representa menos de 1% do uso atual do 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
fonte
2

Talvez você precise de um intervalo selecionado além da posição do cursor. Aqui está uma função simples, você nem precisa do 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 você queira chamá-lo em uma entrada sempre que ele mudar ou o mouse mover a posição do cursor (neste caso, estamos usando o jQuery .on()). Por motivos de desempenho, pode ser uma boa ideia adicionar setTimeout()ou algo como Sublinhados _debounce()se os eventos estiverem chegando:

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

Aqui está um violino, se você quiser experimentá-lo: https://jsfiddle.net/Dhaupin/91189tq7/

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