W3docs

JavaScript Selection und Range API

Erfahren Sie, wie Sie mit der JavaScript Selection und Range API Text im DOM auswählen, markieren, extrahieren und einfügen können.

Wenn ein Benutzer den Cursor über Text auf einer Seite zieht, verfolgt der Browser, was ausgewählt wurde. JavaScript stellt diese Informationen zur Verfügung — und erlaubt es Ihnen, Auswahlen selbst zu erstellen — über zwei verwandte DOM-Schnittstellen:

  • Ein Range ist ein Paar von Begrenzungspunkten (ein Start und ein Ende) innerhalb des Dokuments. Er beschreibt welchen Teil des Dokuments Sie meinen, bis hin zu einem bestimmten Zeichenoffset innerhalb eines Textknotens. Ein Range kann rein im Speicher existieren, ohne dass der Benutzer davon weiß.
  • Eine Selection ist das, was der Benutzer gerade markiert hat. Sie ist im Wesentlichen eine Hülle um einen oder mehrere Ranges, die mit der Markierung auf dem Bildschirm und dem Cursor (Texteinfügemarke) verbunden ist.

Sie greifen auf diese APIs zurück, wenn Sie einen Rich-Text-Editor, eine „Markieren und kommentieren"-Funktion, ein benutzerdefiniertes Suchen-und-Ersetzen oder alles bauen müssen, das ausgewählten Text programmgesteuert liest, verschiebt oder gestaltet. Dieses Kapitel behandelt das Erstellen von Ranges, das Lesen und Ändern der Benutzerauswahl sowie das Zusammenspiel beider Konzepte, um Inhalte zu markieren und einzufügen.

Dies baut auf der Struktur des DOM auf. Wenn Ihnen Knotentypen und Offsets neu sind, lesen Sie zuerst Node-Eigenschaften: Typ, Tag und Inhalt und Das Dokument modifizieren.

Die Selection-Schnittstelle verstehen

Die Selection-Schnittstelle repräsentiert den Text, den der Benutzer markiert hat, oder die aktuelle Position der Einfügemarke, wenn nichts markiert ist. Sie greifen darauf mit der globalen Methode window.getSelection() zu (oft einfach getSelection()). Intern hält eine Selection null oder mehr Range-Objekte; in der Praxis halten die meisten Browser nur einen einzigen Range, sodass getRangeAt(0) die gängige Methode zum Lesen ist.

Der schnellste Weg zu sehen, was ausgewählt ist, ist toString(), das den ausgewählten Text als einfachen string zurückgibt:

// After the user highlights something on the page:
const selectedText = window.getSelection().toString();
console.log(selectedText); // whatever the user highlighted

Nützliche Eigenschaften und Methoden von Selection

  • rangeCount: Die Anzahl der Ranges in der Selection — 0, wenn nichts ausgewählt ist. Überprüfen Sie dies immer, bevor Sie getRangeAt aufrufen.
  • toString(): Gibt den ausgewählten Text als string zurück.
  • getRangeAt(index): Gibt den Range am angegebenen Index zurück (verwenden Sie 0 für die aktuelle Auswahl).
  • addRange(range): Fügt einen Range zur Selection hinzu und markiert ihn auf dem Bildschirm.
  • removeAllRanges(): Löscht die Selection vollständig.
  • removeRange(range): Entfernt einen bestimmten Range. Da die meisten Browser nur einen einzigen Range halten, ist removeAllRanges() die praktischere Wahl.
  • collapse(node, offset): Reduziert die Selection auf einen einzelnen Punkt (eine leere Einfügemarke) innerhalb von node.

Ein gängiges Muster ist, die aktuelle Selection zu lesen, sie zu modifizieren und dann eine neue Selection zurückzuschreiben — removeAllRanges() gefolgt von addRange().

Praktisches Beispiel: Text markieren

Um das zu markieren, was der Benutzer ausgewählt hat, nehmen Sie dessen Range, ziehen Sie die ausgewählten Knoten aus dem Dokument heraus, hüllen Sie sie in ein gestaltetes <span> ein und legen Sie dieses span wieder an die Stelle, an der der Inhalt war.

extractContents() entfernt den ausgewählten Inhalt aus dem DOM und gibt ihn als document fragment zurück, wodurch der Range an dieser Stelle leer (kollabiert) bleibt — genau dort fügen wir dann das span ein.

<div id="text">Select some of this text and press the button.</div>
<button onclick="highlightText()">Highlight</button>

<script>
function highlightText() {
  const selection = window.getSelection();
  if (!selection.rangeCount) return false;
  const range = selection.getRangeAt(0);
  const span = document.createElement('span');
  span.style.backgroundColor = 'yellow';
  const fragment = range.extractContents();
  span.appendChild(fragment);
  range.insertNode(span);
}
</script>

Die Range-Schnittstelle erkunden

Ein Range markiert ein Fragment des Dokuments mit zwei Begrenzungspunkten — einem Start und einem Ende — die jeweils durch einen Knoten und einen Offset definiert werden. Die Bedeutung des Offsets hängt vom Knoten ab:

  • Innerhalb eines Textknotens ist der Offset ein Zeichenindex (z. B. ist Offset 5 zwischen dem 5. und 6. Zeichen).
  • Innerhalb eines Elementknotens zählt der Offset die Kindknoten (z. B. ist Offset 0 vor dem ersten Kind).

Erstellen Sie einen leeren Range mit document.createRange() und positionieren Sie dann seine Grenzen. Sie können die Knoten, auf die Sie zeigen möchten, mit getElementById / querySelector finden.

Grenzen setzen

const p = document.querySelector('p');
const textNode = p.firstChild;        // the text inside <p>

const range = document.createRange();
range.setStart(textNode, 0);          // start at the first character
range.setEnd(textNode, 5);            // end before the 6th character
console.log(range.toString());        // first 5 characters of the paragraph

Zwei Abkürzungen decken die häufigsten Fälle ab, sodass Sie keine Offsets berechnen müssen:

  • selectNode(node) — der Range umspannt den Knoten und seine umgebenden Tags.
  • selectNodeContents(node) — der Range umspannt nur das, was innerhalb des Knotens ist.

Nützliche Methoden von Range

  • setStart(node, offset) / setEnd(node, offset): Positionieren Sie die Start- und Endgrenzen.
  • selectNode(node) / selectNodeContents(node): Setzen Sie beide Grenzen um einen Knoten oder dessen Inhalt.
  • toString(): Der Text innerhalb des Range.
  • cloneContents(): Gibt eine Kopie des Inhalts des Range als document fragment zurück, ohne das Dokument zu verändern.
  • extractContents(): Verschiebt den Inhalt aus dem Dokument in ein Fragment und gibt es zurück.
  • deleteContents(): Entfernt den Inhalt des Range und gibt nichts zurück.
  • cloneRange(): Gibt eine Kopie des Range-Objekts selbst zurück (nicht seines Inhalts).
  • insertNode(node): Fügt einen Knoten am Anfang des Range ein.
  • surroundContents(node): Hüllt den Inhalt des Range in node ein — praktisch zum Markieren, wirft aber einen Fehler, wenn der Range einen Nicht-Text-Element teilweise kreuzt.

Denken Sie an den Unterschied: cloneContents() kopiert, extractContents() verschiebt heraus und gibt zurück, deleteContents() entfernt und verwirft.

Praktisches Beispiel: Text extrahieren

Dieses Beispiel liest alles innerhalb eines Elements mit einem Range und transformiert den Text, ohne den ursprünglichen DOM zu berühren:

<div id="content">This is some sample text for extraction.</div>
<button onclick="extractText()">Extract and Manipulate</button>

<script>
function extractText() {
  const range = document.createRange();
  const content = document.getElementById('content');
  range.selectNodeContents(content);
  const extractedText = range.toString();
  const manipulatedText = extractedText.replace('sample', 'example'); // Manipulating text
  alert(manipulatedText);
}
</script>

Im obigen Beispiel ersetzt das Skript das Wort „sample" durch „example" im extrahierten Text, bevor es in einer Alertbox angezeigt wird. Dies ist eine einfache Manipulation, zeigt aber, wie Sie mit dem extrahierten Text arbeiten können.

Erweiterte Textoperationen

Über die grundlegende Textmanipulation hinaus ermöglichen die Selection- und Range-Schnittstellen komplexere Operationen wie das direkte Einfügen von Knoten in das Dokument.

Beispiel: Text einfügen

Dieses Beispiel verwendet ein contenteditable-div: Der Benutzer klickt, um die Einfügemarke zu setzen, und die Schaltfläche fügt 'Hello World' genau an dieser Stelle ein. Beachten Sie, wie deleteContents() zuerst alles Ausgewählte entfernt, dann der neue Textknoten eingefügt und neu ausgewählt wird, sodass die Einfügemarke dahinter landet.

<div id="editable" contenteditable="true" style="border: 1px solid #ccc; padding: 10px; min-height: 50px;">
  Click here and set the cursor position.
</div>
<button onclick="insertText()">Insert 'Hello World'</button>

<script>
function insertText() {
  const editableDiv = document.getElementById('editable');
  const sel = window.getSelection();
  
  // Check if the selection is within the editable div
  if (!sel.rangeCount || !editableDiv.contains(sel.getRangeAt(0).commonAncestorContainer)) return;
  
  const range = sel.getRangeAt(0);
  range.deleteContents();  // Clears any selected text

  const textNode = document.createTextNode('Hello World');
  range.insertNode(textNode);

  sel.removeAllRanges();   // Clear the previous selection
  sel.addRange(range);     // Re-select the new text node
}
</script>

Zusammenfassung

  • Ein Range besteht aus zwei Begrenzungspunkten (Knoten + Offset), die ein Fragment des Dokuments beschreiben; erstellen Sie einen mit document.createRange() und positionieren Sie ihn mit setStart/setEnd oder den Abkürzungen selectNode/selectNodeContents.
  • Eine Selection, über window.getSelection(), umhüllt die Markierung des Benutzers auf dem Bildschirm. Lesen Sie sie mit toString() und getRangeAt(0); schreiben Sie sie mit removeAllRanges() + addRange() neu.
  • Für Inhalte: cloneContents() kopiert, extractContents() verschiebt heraus, deleteContents() verwirft, und insertNode / surroundContents fügen Knoten wieder ein.

Zusammen ermöglichen diese Methoden das präzise Markieren, Extrahieren und Einfügen von Inhalten — die Grundlage von Rich-Text-Editoren und Annotationswerkzeugen.

Weiter lernen: Das Dokument modifizieren · Node-Eigenschaften: Typ, Tag und Inhalt · Suchen: getElement* und querySelector

Übungen

Übung
Welche der folgenden Aussagen über die JavaScript Range und Selection Schnittstellen sind wahr?
Welche der folgenden Aussagen über die JavaScript Range und Selection Schnittstellen sind wahr?
Was this page helpful?