Signatur
Beschreibung
Ein Text-Knoten enthält den reinen Textinhalt eines Elements, ohne HTML-Auszeichnung. Er erbt von CharacterData und damit auch von Node und EventTarget. Sein nodeType ist Node.TEXT_NODE (Wert 3), sein nodeName ist immer "#text". Der eigentliche Inhalt steht in data bzw. nodeValue oder textContent.
Textknoten entstehen automatisch beim Parsen von HTML. Das gilt auch für Leerraum zwischen Tags, zum Beispiel Zeilenumbrüche und Einrückungen. Selbst anlegen lassen sie sich mit new Text(data) oder document.createTextNode(data). Weil ihr Inhalt nie als HTML ausgewertet wird, eignen sie sich gut, um Benutzereingaben sicher in die Seite einzufügen.
Wichtige Mitglieder:
Text.prototype.splitText(offset)– teilt den Knoten an einer Stelle und gibt den neuen, rechten Knoten zurück.Text.prototype.wholeText– der zusammengesetzte Text aller direkt benachbarten Textknoten (nur lesbar).Text.prototype.assignedSlot– das<slot>-Element im Shadow DOM, dem der Knoten zugewiesen ist, sonstnull.- Von
CharacterDatageerbt:data,length,appendData(),insertData(),deleteData(),replaceData(),substringData(),before(),after(),remove().
Typische Einsatzfälle sind Textbausteine in Vorlagen und Such-Hervorhebungen (splitText zusammen mit einem umschließenden <mark>). Auch beim Durchlaufen des DOM mit TreeWalker und NodeFilter.SHOW_TEXT hat man mit Textknoten zu tun.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $data | string | "" | Nur beim Konstruktor new Text(data): der Anfangsinhalt des Textknotens. Andere Werte als Strings werden in einen String umgewandelt. |
Rückgabewert
new Text() gibt einen neuen, noch nicht eingehängten Textknoten zurück. Seine ownerDocument-Eigenschaft zeigt auf das Dokument des aktuellen globalen Objekts.Beispiele
Textknoten anlegen und Benutzereingabe sicher einfügen
const userInput = '<img src=x onerror=alert(1)>';
const p = document.createElement('p');
// Wird nie als HTML ausgewertet, dadurch XSS-sicher
const node = new Text(userInput);
p.append(node);
document.body.append(p);
console.log(node.nodeType === Node.TEXT_NODE, node.nodeName);
console.log(p.innerHTML);
splitText und wholeText
const p = document.createElement('p');
p.append(new Text('Hallo Welt'));
const left = p.firstChild;
const right = left.splitText(5); // teilt vor dem Leerzeichen
console.log(p.childNodes.length);
console.log(JSON.stringify(left.data), JSON.stringify(right.data));
console.log(left.wholeText);
p.normalize(); // benachbarte Textknoten wieder zusammenführen
console.log(p.childNodes.length);
Suchbegriff mit <mark> hervorheben
const highlight = (root, term) => {
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
const hits = [];
while (walker.nextNode()) {
if (walker.currentNode.data.includes(term)) hits.push(walker.currentNode);
}
// Erst sammeln, dann ändern, damit der Walker nicht durcheinanderkommt
for (const textNode of hits) {
const start = textNode.data.indexOf(term);
const match = textNode.splitText(start);
match.splitText(term.length);
const mark = document.createElement('mark');
match.replaceWith(mark);
mark.append(match);
}
return hits.length;
};
document.body.innerHTML = '<p>JavaScript ist toll. Ich mag JavaScript.</p>';
console.log(highlight(document.body, 'JavaScript'));
console.log(document.body.innerHTML);
Leerraum-Textknoten herausfiltern
document.body.innerHTML = `<ul>
<li>A</li>
<li>B</li>
</ul>`;
const ul = document.querySelector('ul');
console.log(ul.childNodes.length); // enthält Leerraum-Knoten
const whitespace = [...ul.childNodes]
.filter((n) => n.nodeType === Node.TEXT_NODE && !n.data.trim());
console.log(whitespace.length, ul.children.length);
// Wichtig · Fallstricke
- Leerraum zählt: Zeilenumbrüche und Einrückungen im HTML werden zu eigenen Textknoten. Deshalb ist
firstChildoderchildNodes[0]oft ein Textknoten und kein Element. Für reine Elemente sindfirstElementChildundchildrendie bessere Wahl. - Sicherheit: Mit
new Text(),createTextNode()odertextContenteingefügter Text wird nicht als HTML ausgewertet. Für Benutzereingaben ist das die sichere Alternative zuinnerHTML, weil es XSS verhindert. In Kontexten wie<script>,<style>oder Attributen wiehref="javascript:…"schützt es aber nicht. - Nicht mit dem Format
text/plainverwechseln: DasText-Interface ist nur der DOM-Knotentyp. Seine Unterklassen sindCDATASection(nur in XML) und die Unterschiede zuCommentsind klein, denn beide erben vonCharacterData. - splitText: Liegt
offsetüberlength, wird einIndexSizeErrorgeworfen. Die Methode zählt in UTF-16-Codeeinheiten, sodass Emojis und andere Ersatzpaare (Surrogate) zerteilt werden können. wholeTextist nur lesbar. Das früher vorgesehenereplaceWholeText()wurde entfernt.- Kompatibilität: Das Interface wird in allen Browsern unterstützt. Der Konstruktor
new Text()fehlt nur im alten Internet Explorer, dort hilftdocument.createTextNode().assignedSlotbraucht Shadow-DOM-Unterstützung. - Leistung: Viele Änderungen an einzelnen Textknoten lösen jeweils ein Neuzeichnen der Seite aus. Besser bündelt man sie in einem
DocumentFragmentoder setzt einmaltextContent.