Legen Sie die Tastatur-Caret-Position im HTML-Textfeld fest

173

Weiß jemand, wie man das Tastatur-Caret in einem Textfeld an eine bestimmte Position bewegt?

Wenn beispielsweise ein Textfeld (z. B. Eingabeelement, kein Textbereich) 50 Zeichen enthält und ich das Caret vor Zeichen 20 positionieren möchte, wie würde ich vorgehen?

Dies unterscheidet sich von dieser Frage: jQuery Setzt die Cursorposition im Textbereich , für die jQuery erforderlich ist.

Jonhobbs
quelle

Antworten:

205

Auszug aus Josh Stodolas Einstellung Tastatur-Caret-Position in einer Textbox oder TextArea mit Javascript

Eine generische Funktion, mit der Sie das Caret an einer beliebigen Position eines Textfelds oder Textbereichs einfügen können, die Sie möchten:

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();
        }
    }
}

Der erste erwartete Parameter ist die ID des Elements, in das Sie das Tastatur-Caret einfügen möchten. Wenn das Element nicht gefunden werden kann, passiert (offensichtlich) nichts. Der zweite Parameter ist der Caret-Positon-Index. Zero setzt das Tastatur-Caret am Anfang. Wenn Sie eine Zahl übergeben, die größer als die Anzahl der Zeichen im Elementwert ist, wird das Tastatur-Caret am Ende platziert.

Getestet auf IE6 und höher, Firefox 2, Opera 8, Netscape 9, SeaMonkey und Safari. Leider funktioniert es auf Safari nicht in Kombination mit dem Onfocus-Ereignis.

Ein Beispiel für die Verwendung der obigen Funktion, um das Tastatur-Caret zu zwingen, zum Ende aller Textbereiche auf der Seite zu springen, wenn sie den Fokus erhalten:

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
quelle
4
if(elem.selectionStart)bricht ab, wenn selectionStart 0 ist, wie auch in der Antwort von jhnns hervorgehoben.
Mpartel
1
Das funktioniert bei mir nicht. Wenn ich auf das eigentliche Textfeld klicke, erwarte ich, dass die Caret-Position am Anfang steht. Überprüfen Sie heraus meine Geige jsfiddle.net/khx2w
elad.chen
Die Funktion setCaretPosition funktioniert einwandfrei. Ihre addActionHandler-Funktion funktioniert jedoch nicht. Aber auch ohne das konnte ich den Cursor nicht dazu bringen, sich auf den Fokus zu bewegen. Dies liegt höchstwahrscheinlich daran, dass der Browser die Cursorposition selbst basierend auf der Position des Klicks festlegt. Es scheint keinen Weg zu geben, was ich sagen kann, aber ich könnte völlig falsch liegen.
GJK
Funktioniert in IE9, FF25, aber nicht in Chrome 30. Besser als keine!
Umber Ferrule
Ich habe elem.value = elem.value.replace(/^9/g,'+79')im Code. Auf OperaMINI Cursor nach +. Diese Funktion hilft nicht
eri
52

Der Link in der Antwort ist defekt, dieser sollte funktionieren (alle Credits gehen an blog.vishalon.net ):

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

Für den Fall, dass der Code erneut verloren geht, sind hier die beiden Hauptfunktionen:

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();
 }
}
ewig
quelle
1
+1 für die Basisfunktionen, obwohl einige Anpassungen vorgenommen werden müssen . Die Anzahl der Zeilen muss bei Verwendung der Bereichsmethode von "pos" abgezogen werden.
Rob W
36

Da ich diese Lösung wirklich brauchte und die typische Basislösung ( Eingabe fokussieren - dann Wert auf sich selbst setzen ) nicht browserübergreifend funktioniert , habe ich einige Zeit damit verbracht, alles zu optimieren und zu bearbeiten, damit es funktioniert. Aufbauend auf dem Code von @ kd7 habe ich mir Folgendes ausgedacht .

Genießen! Funktioniert in IE6 +, Firefox, Chrome, Safari, Opera

Browserübergreifende Caret-Positionierungstechnik (Beispiel: Bewegen des Cursors auf ENDE)

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

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

Das Fleisch und die Kartoffeln sind im Grunde genommen die SetCaretPosition von @ kd7 , wobei die größte Verbesserung darin besteht if (el.selectionStart || el.selectionStart === 0), dass in Firefox der SelectionStart bei 0 beginnt , was in Boolean natürlich zu False wird, also brach er dort.

In Chrome war das größte Problem, dass es .focus()nicht genug war, es nur zu geben (es wurde immer der gesamte Text ausgewählt!). Daher setzen wir den Wert von sich selbst auf sich selbst, el.value = el.value;bevor wir unsere Funktion aufrufen, und jetzt hat es einen Griff und eine Position mit dem Eingabe zur Verwendung von 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
quelle
@mcpDESIGNS Ich versuche, diese Funktion zu verwenden, wenn ein Fokus auf eine Texteingabe gelegt wird, aber ich komme nicht weiter. Könnten Sie bitte bei der Anwendung dieser Funktion mit reinem Javascript helfen?
elad.chen
@ elad.chen Versuchen Sie, sie am Ende des Textfelds zu positionieren, sobald sie sich darauf konzentrieren?
Mark Pieszak - Trilon.io
@mcpDESIGNS Ich möchte den Cursor am Anfang des Feldes platzieren, sobald das Element fokussiert wird. Siehe die Geige: jsfiddle.net/KuLTU/3
elad.chen
@ elad.chen Entschuldigung für die verrückte späte Antwort! Ändern Sie einfach dieses Ereignis in .onclickanstatt .onfocusinnerhalb Ihrer search_field_focus-Funktion
Mark Pieszak - Trilon.io
2
el.value = el.value; [...] if(el !== null)- Ich würde diese beiden Zeilen tauschen. Wenn elnull ist, el.value = el.valueschlägt dies fehl, sodass sich diese Zeile innerhalb von befinden sollte if.
BackSlash
21

Ich habe die Antwort von kd7 ein wenig angepasst, da elem.selectionStart als false ausgewertet wird, wenn der selectionStart übrigens 0 ist.

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

Ich habe einen einfachen Weg gefunden, um dieses in IE und Chrome getestete Problem zu beheben:

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

Übergeben Sie die Textfeld-ID und die Caret-Position an diese Funktion.

Iam_NSA
quelle
3

Wenn Sie ein Textfeld fokussieren müssen und Ihr einziges Problem darin besteht, dass der gesamte Text hervorgehoben wird, während das Caret am Ende stehen soll, können Sie in diesem speziellen Fall diesen Trick verwenden, um den Textfeldwert nach dem Fokus auf sich selbst zu setzen:

$("#myinputfield").focus().val($("#myinputfield").val());
manish_s
quelle
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
quelle
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
quelle
Nicht gefangener TypeError: Objekt [Objekt HTMLInputElement] hat keine Methode 'StartsWith'
Bobpaul
1
@bobpaul: tIDsollte die ID des Elements sein, nicht das Elementobjekt selbst. Wenn Sie das Elementobjekt übergeben, können Sie bei dieser Methode einfach die beiden ersten Zeilen entfernen, und es funktioniert.
Ehrfurcht
2

Ich würde die Bedingungen wie folgt beheben:

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
quelle