Start · Sprachen · JavaScript · Referenz · Text

Text

Schnittstelle

Das <code>Text</code>-Interface steht für einen Textknoten im DOM-Baum, also für den reinen Textinhalt eines Elements oder Attributs.

seit JavaScript Baseline: alle Browser (DOM Level 1; Konstruktor s Kategorie: webapi

Signatur

interface Text extends CharacterData

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, sonst null.
  • Von CharacterData geerbt: 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

Typ
Text
Beschreibung
Der Konstruktor 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);
true "#text" &lt;img src=x onerror=alert(1)&gt;

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);
2 "Hallo" " Welt" Hallo Welt 1

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);
1 <p><mark>JavaScript</mark> ist toll. Ich mag JavaScript.</p>

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);
5 3 2

// Wichtig · Fallstricke

  • Leerraum zählt: Zeilenumbrüche und Einrückungen im HTML werden zu eigenen Textknoten. Deshalb ist firstChild oder childNodes[0] oft ein Textknoten und kein Element. Für reine Elemente sind firstElementChild und children die bessere Wahl.
  • Sicherheit: Mit new Text(), createTextNode() oder textContent eingefügter Text wird nicht als HTML ausgewertet. Für Benutzereingaben ist das die sichere Alternative zu innerHTML, weil es XSS verhindert. In Kontexten wie <script>, <style> oder Attributen wie href="javascript:…" schützt es aber nicht.
  • Nicht mit dem Format text/plain verwechseln: Das Text-Interface ist nur der DOM-Knotentyp. Seine Unterklassen sind CDATASection (nur in XML) und die Unterschiede zu Comment sind klein, denn beide erben von CharacterData.
  • splitText: Liegt offset über length, wird ein IndexSizeError geworfen. Die Methode zählt in UTF-16-Codeeinheiten, sodass Emojis und andere Ersatzpaare (Surrogate) zerteilt werden können.
  • wholeText ist nur lesbar. Das früher vorgesehene replaceWholeText() wurde entfernt.
  • Kompatibilität: Das Interface wird in allen Browsern unterstützt. Der Konstruktor new Text() fehlt nur im alten Internet Explorer, dort hilft document.createTextNode(). assignedSlot braucht 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 DocumentFragment oder setzt einmal textContent.