Programmgesteuert Text in einem inhaltsbearbeitbaren HTML-Element auswählen?

118

In JavaScript ist es möglich, Text in einem inputoder textareaElement programmgesteuert auszuwählen . Sie können eine Eingabe mit fokussieren ipt.focus()und dann ihren Inhalt mit auswählen ipt.select(). Sie können sogar einen bestimmten Bereich mit auswählen ipt.setSelectionRange(from,to).

Meine Frage ist: Gibt es eine Möglichkeit, dies auch in einem contenteditableElement zu tun ?

Ich habe festgestellt, dass ich elem.focus()das Caret in ein contenteditableElement einfügen kann , aber anschließend elem.select()funktioniert das Laufen nicht (und auch nicht setSelectionRange). Ich kann im Web nichts darüber finden, aber vielleicht suche ich nach dem Falschen ...

Wenn es einen Unterschied macht, muss es übrigens nur in Google Chrome funktionieren, da dies für eine Chrome-Erweiterung gilt.

Callum
quelle

Antworten:

170

Wenn Sie den gesamten Inhalt eines Elements (inhaltlich bearbeitbar oder nicht) in Chrome auswählen möchten, gehen Sie wie folgt vor. Dies funktioniert auch in Firefox, Safari 3+, Opera 9+ (möglicherweise auch in früheren Versionen) und IE 9. Sie können auch eine Auswahl bis zur Zeichenebene erstellen. Die APIs, die Sie benötigen, sind DOM-Bereich (aktuelle Spezifikation ist DOM Level 2 , siehe auch MDN ) und Auswahl, die als Teil einer neuen Bereichsspezifikation ( MDN-Dokumente ) angegeben wird.

function selectElementContents(el) {
    var range = document.createRange();
    range.selectNodeContents(el);
    var sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);
}

var el = document.getElementById("foo");
selectElementContents(el);
Tim Down
quelle
15
Für zusätzliche Kompatibilität sollten Sie selectElementContents()einen setTimeout()oder einen Anruf requestAnimationFrame()von einem anrufen onfocus. Siehe jsfiddle.net/rudiedirkx/MgASG/1/show
Rudie
@ Dylan: Ich bin nicht sicher: Die Frage erwähnt, dass das OP bereits verwendet focus().
Tim Down
4
@ Rudie Kompatibilität für welche Anwendung?
Yckart
Funktioniert hervorragend auf dem Desktop. Funktioniert auf mobilen Browsern nicht. Keine Auswahl getroffen. Versuchte Safari und Chrome auf dem iPhone iOS 11.
Campbell
1
@campbell: Es funktioniert auf Safari zumindest unter iOS, vorausgesetzt, Sie haben bereits eine Auswahl . Andernfalls nein, der Browser erlaubt JavaScript einfach nicht, eine Auswahl anzuzeigen, vermutlich aus Gründen der Benutzererfahrung.
Tim Down
34

Zusätzlich zu Tim Downs Antwort habe ich eine Lösung entwickelt, die auch in oldIE funktioniert:

var selectText = function() {
  var range, selection;
  if (document.body.createTextRange) {
    range = document.body.createTextRange();
    range.moveToElementText(this);
    range.select();
  } else if (window.getSelection) {
    selection = window.getSelection();
    range = document.createRange();
    range.selectNodeContents(this);
    selection.removeAllRanges();
    selection.addRange(range);
  }
};

document.getElementById('foo').ondblclick = selectText;​

Getestet in IE 8+, Firefox 3+, Opera 9+ und Chrome 2+. Sogar ich habe es in einem jQuery-Plugin eingerichtet:

jQuery.fn.selectText = function() {
  var range, selection;
  return this.each(function() {
    if (document.body.createTextRange) {
      range = document.body.createTextRange();
      range.moveToElementText(this);
      range.select();
    } else if (window.getSelection) {
      selection = window.getSelection();
      range = document.createRange();
      range.selectNodeContents(this);
      selection.removeAllRanges();
      selection.addRange(range);
    }
  });
};

$('#foo').on('dblclick', function() {
  $(this).selectText();
});

... und wer interessiert ist, hier ist das gleiche für alle Kaffee-Junkies:

jQuery.fn.selectText = ->
  @each ->
    if document.body.createTextRange
      range = document.body.createTextRange()
      range.moveToElementText @
      range.select()
    else if window.getSelection
      selection = window.getSelection()
      range = document.createRange()
      range.selectNodeContents @
      selection.removeAllRanges()
      selection.addRange range
    return

Aktualisieren:

Wenn Sie die gesamte Seite oder den Inhalt eines bearbeitbaren Bereichs (gekennzeichnet mit contentEditable) auswählen möchten , können Sie dies viel einfacher tun, indem Sie zu Folgendem wechseln designModeund Folgendes verwenden document.execCommand:

Es gibt einen guten Ausgangspunkt bei MDN und eine kleine Dokumentation .

var selectText = function () {
  document.execCommand('selectAll', false, null);
};

(Funktioniert gut in IE6 +, Opera 9+, Firefoy 3+, Chrome 2+) http://caniuse.com/#search=execCommand

yckart
quelle
10

Da sich alle vorhandenen Antworten mit divElementen befassen , werde ich erklären, wie es mit spans geht.

Es gibt einen subtilen Unterschied bei der Auswahl eines Textbereichs in a span. Um den Textstart- und -endindex übergeben zu können, müssen Sie einen TextKnoten verwenden, wie hier beschrieben :

Wenn der startNode ein Knoten vom Typ Text, Comment oder CDATASection ist, ist startOffset die Anzahl der Zeichen ab dem Start von startNode. Bei anderen Knotentypen ist startOffset die Anzahl der untergeordneten Knoten zwischen dem Start des startNode.

var e = document.getElementById("id of the span element you want to select text in");
var textNode = e.childNodes[0]; //text node is the first child node of a span

var r = document.createRange();
var startIndex = 0;
var endIndex = textNode.textContent.length;
r.setStart(textNode, startIndex);
r.setEnd(textNode, endIndex);

var s = window.getSelection();
s.removeAllRanges();
s.addRange(r);
Domysee
quelle
Wirklich sollte sein: r.setStart(e.firstChild,0); r.setEnd(e.lastChild,e.lastChild.textContent.length); Natürlich sollten Sie überprüfen, ob e.firstChild tatsächlich nicht null ist.
Yorick
2
Es gibt keinen Unterschied zwischen einer Auswahl in a <div>und einem <span>Element. Zumindest nicht so, wie Sie es beschreiben.
Tim Down
Es gibt Unterschiede zwischen div und span. In einigen Fällen funktioniert eine Lösung für div nicht richtig in span. Wenn Sie beispielsweise programmgesteuert Text mit div-Lösung auswählen und dann neuen Inhalt einfügen, wird nicht der gesamte Text, sondern nur ein Teil ersetzt, und es gibt Unterschiede zwischen Chrome und Firefox
Neosonne
6

Mit Rangy können Sie diesen Cross-Browser mit demselben Code ausführen. Rangy ist eine browserübergreifende Implementierung der DOM-Methoden zur Auswahl. Es ist gut getestet und macht dies viel weniger schmerzhaft. Ich weigere mich, Contenteditable ohne es zu berühren.

Rangy finden Sie hier:

http://code.google.com/p/rangy/

Mit rangy in Ihrem Projekt können Sie dies immer schreiben, auch wenn der Browser IE 8 oder früher ist und eine völlig andere native API für die Auswahl hat:

var range = rangy.createRange();
range.selectNodeContents(contentEditableNode);
var sel = rangy.getSelection();
sel.removeAllRanges();
sel.addRange(range);

Wobei "contentEditableNode" der DOM-Knoten ist, der das Attribut contenteditable hat. Sie könnten es so holen:

var contentEditable = document.getElementById('my-editable-thing');

Oder wenn jQuery bereits Teil Ihres Projekts ist und Sie es bequem finden:

var contentEditable = $('.some-selector')[0];
Tom Boutell
quelle
Das Rangy-Projekt ist jetzt nach Github umgezogen: github.com/timdown/rangy
tanius
3

Die moderne Art, Dinge zu tun, ist so. Weitere Details zu MDN

document.addEventListener('dblclick', (event) => {
  window.getSelection().selectAllChildren(event.target)
})
<div contenteditable="true">Some text</div>


quelle
Danke, das funktioniert super! Fwiw, diese MDN-Seite markiert diese Technologie als experimentell. Aber es funktioniert in der aktuellen Version von Chrome und FF im Juni 2020.
JohnK
2

[Aktualisiert, um Fehler zu beheben]

Hier ist ein Beispiel, das aus dieser Antwort übernommen wurde und in Chrome gut zu funktionieren scheint - Wählen Sie den Bereich in contenteditable div aus

var elm = document.getElementById("myText"),
    fc = elm.firstChild,
    ec = elm.lastChild,
    range = document.createRange(),
    sel;
elm.focus();
range.setStart(fc,1);
range.setEnd(ec,3);
sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);

HTML ist:

<div id="myText" contenteditable>test</div>
patorjk
quelle