inhaltsbearbeitbar, Caret am Ende des Textes setzen (browserübergreifend)


111

Ausgabe in Chrome :

<div id="content" contenteditable="true" style="border:1px solid #000;width:500px;height:40px;">
    hey
    <div>what's up?</div>
<div>
<button id="insert_caret"></button>

Ich glaube an FF würde es ungefähr so ​​aussehen:

hey
<br />
what's up?

und im IE :

hey
<p>what's up?</p>

Leider gibt es keine gute Möglichkeit, es so zu machen, dass jeder Browser ein <br />anstelle eines div- oder p-Tags einfügt, oder zumindest konnte ich online nichts finden.


Jedenfalls versuche ich jetzt, wenn ich auf den Knopf drücke, dass das Caret am Ende des Textes gesetzt wird, also sollte es ungefähr so ​​aussehen:

hey
what's up?|

Wie funktioniert das, damit es in allen Browsern funktioniert ?

Beispiel:

$(document).ready(function()
{
    $('#insert_caret').click(function()
    {
        var ele = $('#content');
        var length = ele.html().length;

        ele.focus();

        //set caret -> end pos
     }
 }

Antworten:


281

Die folgende Funktion funktioniert in allen gängigen Browsern:

function placeCaretAtEnd(el) {
    el.focus();
    if (typeof window.getSelection != "undefined"
            && typeof document.createRange != "undefined") {
        var range = document.createRange();
        range.selectNodeContents(el);
        range.collapse(false);
        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    } else if (typeof document.body.createTextRange != "undefined") {
        var textRange = document.body.createTextRange();
        textRange.moveToElementText(el);
        textRange.collapse(false);
        textRange.select();
    }
}

placeCaretAtEnd( document.querySelector('p') );
p{ padding:.5em; border:1px solid black; }
<p contentEditable>foo bar </p>

Das Platzieren des Carets am Anfang ist nahezu identisch: Es muss lediglich der Boolesche Wert geändert werden, der an die Aufrufe von übergeben wird collapse(). Hier ist ein Beispiel, das Funktionen zum Platzieren des Carets am Anfang und am Ende erstellt:

function createCaretPlacer(atStart) {
    return function(el) {
        el.focus();
        if (typeof window.getSelection != "undefined"
                && typeof document.createRange != "undefined") {
            var range = document.createRange();
            range.selectNodeContents(el);
            range.collapse(atStart);
            var sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
        } else if (typeof document.body.createTextRange != "undefined") {
            var textRange = document.body.createTextRange();
            textRange.moveToElementText(el);
            textRange.collapse(atStart);
            textRange.select();
        }
    };
}

var placeCaretAtStart = createCaretPlacer(true);
var placeCaretAtEnd = createCaretPlacer(false);

Funktioniert nicht mit Chrome, da createTextRange keine Standardfunktion ist. Siehe stackoverflow.com/a/41743191/700206 .
Whitneyland

@Lee: Es funktioniert gut in Chrome, das window.getSelectionund unterstützt document.createRange. Der createTextRangeZweig ist für alte Versionen von Internet Explorer.
Tim Down

Zum Zeitpunkt des Schreibens window.getSelectionwird dies von 0,29% aller Browser nicht unterstützt (IE> 8). siehe: caniuse.com/#search=window.getSelection
w.stoettinger

@ TimDown das funktioniert. +1. Aber können Sie den Code auch erklären, indem Sie bitte Kommentare hinzufügen? Wäre toll
Shinobi

Weiß jemand, wie man das Caret auf das Ende setzt (benutze diesen Code), wenn er versucht, auf ein iframe> body-Element abzuzielen? Das Körperelement hat editablecontent="true"...? placeCaretAtEnd(this);wird nicht für mich arbeiten.
RobbTe

6

Leider hat Tims ausgezeichnete Antwort für mich nur für die Platzierung am Ende funktioniert, für die Platzierung am Anfang musste ich sie leicht modifizieren.

function setCaret(target, isStart) {
  const range = document.createRange();
  const sel = window.getSelection();
  if (isStart){
    const newText = document.createTextNode('');
    target.appendChild(newText);
    range.setStart(target.childNodes[0], 0);
  }
  else {
    range.selectNodeContents(target);
  }
  range.collapse(isStart);
  sel.removeAllRanges();
  sel.addRange(range);
  target.focus();
  target.select();
}

Ich bin mir jedoch nicht sicher, ob focus()und select()tatsächlich benötigt werden.


Sie haben auch eine externe Bibliothek eingeführt. Wenn Sie nicht der Meinung sind, dass Fokus und Auswahl erforderlich sind, können Sie die Zeilen auskommentieren und testen.
Dotnethaggis

Danke, jquery entfernt. Ich erinnere mich, dass ich einige widersprüchliche Ergebnisse hatte. Ich werde versuchen, sie erneut zu isolieren.
Dimid

0

Dieses (Live-) Beispiel zeigt eine kurze einfache Funktion setCaretAtStartEnd, die zwei Argumente akzeptiert. Ein (bearbeitbarer) Knoten zum Platzieren des Carets bei & ein Boolescher Wert, der angibt, wo das Caret platziert werden soll (Anfang oder Ende des Knotens)

const editableElm = document.querySelector('[contenteditable]');

document.querySelectorAll('button').forEach((elm, idx) => 
  elm.addEventListener('click', () => {
    editableElm.focus()
    setCaretAtStartEnd(editableElm, idx) 
  })
)

function setCaretAtStartEnd( node, atEnd ){
  const sel = document.getSelection();
  node = node.firstChild;

  if( sel.rangeCount ){
      ['Start', 'End'].forEach(pos =>
        sel.getRangeAt(0)["set" + pos](node, atEnd ? node.length : 0)
      )
  }
}
[contenteditable]{ padding:5px; border:1px solid; }
<h1 contenteditable>Place the caret anywhere</h1>
<br>
<button>Move caret to start</button>
<button>Move caret to end</button>


-1

Wenn Sie den Google Closure Compiler verwenden, können Sie Folgendes tun (etwas vereinfacht aus Tims Antwort):

function placeCaretAtEnd(el) {
    el.focus();
    range = goog.dom.Range.createFromNodeContents(el);
    range.collapse(false);
    range.select();
}

In ClojureScript ist dasselbe:

(defn place-caret-at-end [el] 
   (.focus el)
   (doto (.createFromNodeContents goog.dom.Range el)
         (.collapse false)
         .select))

Ich habe dies in Chrome, Safari und FireFox getestet und bin mir über den Internet Explorer nicht sicher ...


1
range = goog.dom.Range.createFromNodeContents (el); Was ist goog.dom?
Anh Tú

Das hat bei mir funktioniert. @ AnhTú: goog.dom ist ein Namespace, der von der Closure-Library bereitgestellt wird.
David Beneš
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.