Signatur
Beschreibung
surroundContents() nimmt den Inhalt eines Range-Objekts und legt einen neuen Knoten darum, zum Beispiel ein <mark> oder <strong>. Intern macht die Methode ungefähr das Gleiche wie die Kombination aus extractContents(), insertNode() und appendChild(): Zuerst wird der Inhalt aus dem Dokument herausgelöst. Danach werden alle bisherigen Kindknoten von newParent entfernt, der herausgelöste Inhalt wird in newParent eingehängt, und newParent wird an der Startposition des Bereichs eingefügt. Zum Schluss umfasst der Range genau den neuen Elternknoten.
Typische Anwendungen sind das Hervorheben von Text, den Nutzer markiert haben, Suchtreffer-Markierungen, Anmerkungs-Werkzeuge und einfache Editor-Funktionen wie „Fett“ oder „Kursiv“ in contenteditable-Bereichen.
Wichtige Einschränkung: Der Range darf keinen Nicht-Text-Knoten nur teilweise enthalten. Start und Ende müssen also im selben Element liegen, oder alle betroffenen Elemente müssen komplett im Bereich enthalten sein. Ein Bereich, der mitten in einem <b> anfängt und außerhalb davon endet, löst einen InvalidStateError aus. Textknoten dürfen dagegen teilweise ausgewählt sein; sie werden an den Grenzen automatisch geteilt.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $newParent Pflicht | Node | Der Knoten, der den Inhalt des Bereichs umschließen soll, meist ein neu erzeugtes Element. Er darf nicht vom Typ Document, DocumentType oder DocumentFragment sein. Vorhandene Kindknoten werden vorher entfernt. |
Rückgabewert
undefined). Der Range umfasst danach den Knoten newParent.Beispiele
Einen Textabschnitt mit <mark> hervorheben
// HTML: <p id="text">JavaScript ist vielseitig.</p>
const textNode = document.getElementById('text').firstChild;
const range = document.createRange();
range.setStart(textNode, 14); // "vielseitig" beginnt bei Index 14
range.setEnd(textNode, 24);
const mark = document.createElement('mark');
range.surroundContents(mark);
console.log(document.getElementById('text').innerHTML);
Nutzerauswahl fett formatieren (mit Fehlerbehandlung)
const makeBold = () => {
const selection = window.getSelection();
if (!selection || selection.rangeCount === 0 || selection.isCollapsed) return;
const range = selection.getRangeAt(0);
const strong = document.createElement('strong');
try {
range.surroundContents(strong);
} catch (err) {
if (err.name === 'InvalidStateError') {
// Auswahl schneidet Elementgrenzen: robuster Ausweichweg
strong.appendChild(range.extractContents());
range.insertNode(strong);
} else {
throw err;
}
}
selection.removeAllRanges();
};
document.getElementById('bold-btn').addEventListener('click', makeBold);
Alle Suchtreffer in einem Textknoten markieren
// HTML: <p id="doc">Katze, Hund, Katze, Maus</p>
const highlightAll = (element, term) => {
let node = element.firstChild;
while (node && node.nodeType === Node.TEXT_NODE) {
const idx = node.data.indexOf(term);
if (idx === -1) break;
const range = document.createRange();
range.setStart(node, idx);
range.setEnd(node, idx + term.length);
const mark = document.createElement('mark');
range.surroundContents(mark);
// Nach dem Teilen folgt der Rest-Text hinter <mark>
node = mark.nextSibling;
}
};
highlightAll(document.getElementById('doc'), 'Katze');
console.log(document.getElementById('doc').innerHTML);
// Wichtig · Fallstricke
- InvalidStateError: Wird ausgelöst, wenn der Range einen Nicht-Text-Knoten nur teilweise enthält, zum Beispiel wenn eine Auswahl über mehrere Absätze geht oder mitten in einem
<a>endet. Als Ausweichweg kann manextractContents()zusammen mitinsertNode()verwenden. Das kann aber zusätzliche, aufgeteilte Elemente erzeugen. - InvalidNodeTypeError: Wird ausgelöst, wenn
newParenteinDocument,DocumentTypeoderDocumentFragmentist. - Vorhandene Kinder von
newParentwerden ohne Warnung entfernt. Übergib deshalb am besten immer ein frisch erzeugtes, leeres Element. - Event-Listener und Zustand der verschobenen Knoten bleiben erhalten, denn sie werden verschoben und nicht kopiert. Textknoten an den Grenzen werden aber geteilt. Referenzen auf den ursprünglichen Textknoten zeigen danach nur noch auf den ersten Teil.
- In
contenteditable-Bereichen gehen DOM-Änderungen über Range-Methoden nicht in den Rückgängig-Verlauf (Undo) des Browsers ein. - Browser-Kompatibilität: Die Methode wird von allen modernen Browsern unterstützt, auch von sehr alten Versionen (ab IE 9).