Definir a posição do cursor do teclado na caixa de texto html

173

Alguém sabe como mover o cursor do teclado em uma caixa de texto para uma posição específica?

Por exemplo, se uma caixa de texto (por exemplo, elemento de entrada, não área de texto) possui 50 caracteres e eu quero posicionar o sinal de interpolação antes do caractere 20, como devo proceder?

Isto está na diferenciação desta pergunta: jQuery Defina a posição do cursor na área de texto , que requer jQuery.

jonhobbs
fonte

Respostas:

205

Extraído da Configuração da posição do cursor do teclado de Josh Stodola em uma caixa de texto ou área de texto com Javascript

Uma função genérica que permitirá inserir o cursor em qualquer posição de uma caixa de texto ou área de texto que você desejar:

function setCaretPosition(elemId, caretPos) {
    var elem = document.getElementById(elemId);

    if(elem != null) {
        if(elem.createTextRange) {
            var range = elem.createTextRange();
            range.move('character', caretPos);
            range.select();
        }
        else {
            if(elem.selectionStart) {
                elem.focus();
                elem.setSelectionRange(caretPos, caretPos);
            }
            else
                elem.focus();
        }
    }
}

O primeiro parâmetro esperado é o ID do elemento no qual você deseja inserir o cursor do teclado. Se o elemento não puder ser encontrado, nada acontecerá (obviamente). O segundo parâmetro é o índice de posição do sinal de intercalação. Zero colocará o cursor do teclado no início. Se você passar um número maior que o número de caracteres no valor dos elementos, ele colocará o cursor do teclado no final.

Testado no IE6 e superior, Firefox 2, Opera 8, Netscape 9, SeaMonkey e Safari. Infelizmente, no Safari, ele não funciona em combinação com o evento onfocus).

Um exemplo de uso da função acima para forçar o cursor do teclado a pular para o final de todas as áreas de texto na página quando receberem o foco:

function addLoadEvent(func) {
    if(typeof window.onload != 'function') {
        window.onload = func;
    }
    else {
        if(func) {
            var oldLoad = window.onload;

            window.onload = function() {
                if(oldLoad)
                        oldLoad();

                func();
            }
        }
    }
}

// The setCaretPosition function belongs right here!

function setTextAreasOnFocus() {
/***
 * This function will force the keyboard caret to be positioned
 * at the end of all textareas when they receive focus.
 */
    var textAreas = document.getElementsByTagName('textarea');

    for(var i = 0; i < textAreas.length; i++) {
        textAreas[i].onfocus = function() {
            setCaretPosition(this.id, this.value.length);
        }
    }

    textAreas = null;
}

addLoadEvent(setTextAreasOnFocus);
Ta01
fonte
4
if(elem.selectionStart)quebra quando selectionStart é 0, como também indicado pela resposta de jhnns.
mpartel 01/09/12
1
Isso não funciona para mim. Quando clico na caixa de texto real, espero que a posição do sinal de intercalação esteja no início. Confira meu violino jsfiddle.net/khx2w
elad.chen
A função setCaretPosition funciona perfeitamente. Sua função addActionHandler, no entanto, não. Mas mesmo sem isso, não consegui fazer o cursor mover o foco. Provavelmente, é porque o navegador define a posição do cursor com base na posição do clique. Parece que não há uma maneira de contornar o que posso dizer, mas posso estar completamente errado.
GJK 19/07
Funciona no IE9, FF25, mas não no Chrome 30. Melhor que nenhum!
Umber Ferrule
Eu tenho elem.value = elem.value.replace(/^9/g,'+79')no código. No cursor OperaMINI depois +. esta função não ajuda
eri
52

O link na resposta está quebrado, este deve funcionar (todos os créditos vão para blog.vishalon.net ):

http://snipplr.com/view/5144/getset-cursor-in-html-textarea/

Caso o código se perca novamente, aqui estão as duas funções principais:

function doGetCaretPosition(ctrl)
{
 var CaretPos = 0;

 if (ctrl.selectionStart || ctrl.selectionStart == 0)
 {// Standard.
  CaretPos = ctrl.selectionStart;
 }
 else if (document.selection)
 {// Legacy IE
  ctrl.focus ();
  var Sel = document.selection.createRange ();
  Sel.moveStart ('character', -ctrl.value.length);
  CaretPos = Sel.text.length;
 }

 return (CaretPos);
}


function setCaretPosition(ctrl,pos)
{
 if (ctrl.setSelectionRange)
 {
  ctrl.focus();
  ctrl.setSelectionRange(pos,pos);
 }
 else if (ctrl.createTextRange)
 {
  var range = ctrl.createTextRange();
  range.collapse(true);
  range.moveEnd('character', pos);
  range.moveStart('character', pos);
  range.select();
 }
}
eterno
fonte
1
+1 para as funções básicas, embora alguns ajustes tenham que ser feitos . O número de linhas deve ser subtraído de "pos" ao usar o método range.
Rob W
36

Como eu realmente precisava dessa solução, e a solução típica da linha de base ( concentre a entrada - depois defina o valor igual a si mesma ) não funciona em vários navegadores , passei algum tempo aprimorando e editando tudo para fazê-la funcionar. Com base no código do @ kd7 , aqui está o que eu criei .

Aproveitar! Funciona no IE6 +, Firefox, Chrome, Safari, Opera

Técnica de posicionamento de cursor de cursor entre navegadores (exemplo: movendo o cursor para END)

// ** USEAGE ** (returns a boolean true/false if it worked or not)
// Parameters ( Id_of_element, caretPosition_you_want)

setCaretPosition('IDHERE', 10); // example

A carne e as batatas são basicamente o setCaretPosition do @ kd7 , com o maior ajuste if (el.selectionStart || el.selectionStart === 0), no firefox o selectionStart está começando em 0 , o que, em booleano, é claro, está se voltando para False, então estava chegando lá.

No chrome, o maior problema era que apenas fornecê-lo .focus()não era suficiente (continuava selecionando TODO o texto!) Portanto, definimos o valor de si mesmo el.value = el.value;antes de chamar nossa função, e agora ele tem uma compreensão e posição com o parâmetro entrada para usar selectionStart .

function setCaretPosition(elemId, caretPos) {
    var el = document.getElementById(elemId);

    el.value = el.value;
    // ^ this is used to not only get "focus", but
    // to make sure we don't have it everything -selected-
    // (it causes an issue in chrome, and having it doesn't hurt any other browser)

    if (el !== null) {

        if (el.createTextRange) {
            var range = el.createTextRange();
            range.move('character', caretPos);
            range.select();
            return true;
        }

        else {
            // (el.selectionStart === 0 added for Firefox bug)
            if (el.selectionStart || el.selectionStart === 0) {
                el.focus();
                el.setSelectionRange(caretPos, caretPos);
                return true;
            }

            else  { // fail city, fortunately this never happens (as far as I've tested) :)
                el.focus();
                return false;
            }
        }
    }
}
Mark Pieszak - Trilon.io
fonte
@mcpDESIGNS Estou tentando usar essa função quando o foco é em uma entrada de texto, mas não estou chegando a lugar algum. Você poderia ajudar na aplicação dessa função usando javascript puro?
Elad.chen 19/07/2013
@ elad.chen Você está tentando posicioná-los no final da caixa de texto assim que eles focam nela?
Mark Pieszak # Trilon.io
@mcpDESIGNS Quero colocar o cursor no início do campo assim que o elemento estiver sendo focado. Veja o violino: jsfiddle.net/KuLTU/3
elad.chen 19/07/2013
@ elad.chen Desculpe pela louca resposta tardia! Basta alterar esse evento para .onclick, em vez de .onfocusdentro de sua função search_field_focus
Mark Pieszak - Trilon.io
2
el.value = el.value; [...] if(el !== null)- Eu trocaria essas duas linhas. Se elfor nulo, el.value = el.valuefalhará, de modo que a linha deve estar dentro do if.
BackSlash
21

Eu ajustei a resposta do kd7 um pouco, porque elem.selectionStart será avaliado como falso quando o selectionStart for 0.

function setCaretPosition(elem, caretPos) {
    var range;

    if (elem.createTextRange) {
        range = elem.createTextRange();
        range.move('character', caretPos);
        range.select();
    } else {
        elem.focus();
        if (elem.selectionStart !== undefined) {
            elem.setSelectionRange(caretPos, caretPos);
        }
    }
}
Johannes Ewald
fonte
5

Encontrei uma maneira fácil de corrigir esse problema, testado no IE e no Chrome:

function setCaret(elemId, caret)
 {
   var elem = document.getElementById(elemId);
   elem.setSelectionRange(caret, caret);
 }

Passe o ID da caixa de texto e a posição do cursor para esta função.

Iam_NSA
fonte
3

Se você precisa focar em alguma caixa de texto e seu único problema é que todo o texto fica realçado, enquanto você deseja que o cursor esteja no final, nesse caso específico, você pode usar este truque para definir o valor da caixa de texto para si mesmo após o foco:

$("#myinputfield").focus().val($("#myinputfield").val());
manish_s
fonte
2
<!DOCTYPE html>
<html>
<head>
<title>set caret position</title>
<script type="application/javascript">
//<![CDATA[
window.onload = function ()
{
 setCaret(document.getElementById('input1'), 13, 13)
}

function setCaret(el, st, end)
{
 if (el.setSelectionRange)
 {
  el.focus();
  el.setSelectionRange(st, end);
 }
 else
 {
  if (el.createTextRange)
  {
   range = el.createTextRange();
   range.collapse(true);
   range.moveEnd('character', end);
   range.moveStart('character', st);
   range.select();
  }
 }
}
//]]>
</script>
</head>
<body>

<textarea id="input1" name="input1" rows="10" cols="30">Happy kittens dancing</textarea>

<p>&nbsp;</p>

</body>
</html>
DIpak
fonte
2
function SetCaretEnd(tID) {
    tID += "";
    if (!tID.startsWith("#")) { tID = "#" + tID; }
    $(tID).focus();
    var t = $(tID).val();
    if (t.length == 0) { return; }
    $(tID).val("");
    $(tID).val(t);
    $(tID).scrollTop($(tID)[0].scrollHeight); }
Keith Cromm
fonte
TypeError não detectado: o objeto [objeto HTMLInputElement] não possui o método 'beginWith'
bobpaul
1
@obpapaul: tIDdeve ser o ID do elemento, não o objeto do elemento em si. Se você estiver passando o objeto de elemento, basta remover as 2 primeiras linhas deste método e ele funcionará.
temor
2

Eu fixaria as condições como abaixo:

function setCaretPosition(elemId, caretPos)
{
 var elem = document.getElementById(elemId);
 if (elem)
 {
  if (typeof elem.createTextRange != 'undefined')
  {
   var range = elem.createTextRange();
   range.move('character', caretPos);
   range.select();
  }
  else
  {
   if (typeof elem.selectionStart != 'undefined')
    elem.selectionStart = caretPos;
   elem.focus();
  }
 }
}
Alexander Gavriliuk
fonte