Start · Sprachen · JavaScript · Referenz · TreeWalker

TreeWalker

Schnittstelle

Ein <code>TreeWalker</code> durchläuft die Knoten eines DOM-Unterbaums gefiltert und merkt sich dabei eine Position (<code>currentNode</code>), von der aus man sich frei bewegen kann.

seit JavaScript DOM Level 2 · Baseline: alle Browser Kategorie: webapi

Signatur

interface TreeWalker

Beschreibung

Ein TreeWalker wird über document.createTreeWalker(root, whatToShow, filter) erzeugt. Einen öffentlichen Konstruktor gibt es nicht. Das Objekt bildet eine gefilterte Sicht auf den Unterbaum unterhalb von root. Über whatToShow (Bitmaske aus NodeFilter.SHOW_*) und über eine optionale Filterfunktion legst du fest, welche Knoten diese Sicht enthält.

Anders als NodeIterator, der nur eine flache Reihenfolge vorwärts oder rückwärts durchläuft, erhält der TreeWalker die Baumstruktur. Mit parentNode(), firstChild(), lastChild(), nextSibling() und previousSibling() bewegst du dich strukturell. Mit nextNode() und previousNode() gehst du in Dokumentreihenfolge (Tiefensuche) weiter. Jede Methode gibt den neuen Knoten zurück und setzt currentNode auf ihn. Wird kein passender Knoten gefunden, liefert sie null, und die Position bleibt, wo sie war.

Typische Einsatzfälle sind das Einsammeln aller Textknoten, etwa für Suchen und Hervorheben, Wortzählung oder Übersetzung. Dazu kommen das gezielte Durchlaufen bestimmter Elemente ohne rekursive Hilfsfunktionen und der Umgang mit Kommentarknoten, die querySelectorAll nicht erfasst.

  • Eigenschaften: root (nur lesbar), whatToShow (nur lesbar), filter (nur lesbar), currentNode (lesbar und schreibbar)
  • Methoden: parentNode(), firstChild(), lastChild(), previousSibling(), nextSibling(), previousNode(), nextNode()

Parameter

Name Typ Default Beschreibung
$root Pflicht Node Wurzelknoten des Unterbaums, den der Walker durchläuft. Er ist zugleich der Anfangswert von currentNode. Über root hinaus nach oben kommt der Walker nicht.
$whatToShow number NodeFilter.SHOW_ALL (0xFFFFFFFF) Bitmaske aus NodeFilter-Konstanten, z. B. NodeFilter.SHOW_ELEMENT, NodeFilter.SHOW_TEXT oder NodeFilter.SHOW_COMMENT. Mehrere Werte verknüpfst du mit |.
$filter NodeFilter | ((node: Node) => number) | null null Optionale Funktion oder ein Objekt mit einer Methode acceptNode(node). Rückgabewert ist NodeFilter.FILTER_ACCEPT, FILTER_REJECT (Knoten und sein Unterbaum werden übersprungen) oder FILTER_SKIP (nur der Knoten wird übersprungen, seine Kinder werden weiter geprüft).

Beispiele

Alle Textknoten eines Artikels einsammeln

const article = document.querySelector('article');
const walker = document.createTreeWalker(article, NodeFilter.SHOW_TEXT);

const texts = [];
let node;
while ((node = walker.nextNode())) {
  const text = node.nodeValue.trim();
  if (text) texts.push(text);
}

const wordCount = texts.join(' ').split(/\s+/).length;
console.log(`Wörter im Artikel: ${wordCount}`);
Wörter im Artikel: 842

Filterfunktion: Textknoten in <script>/<style> ausschließen

const walker = document.createTreeWalker(
  document.body,
  NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT,
  (node) => {
    if (node.nodeType === Node.ELEMENT_NODE) {
      // REJECT überspringt das Element samt Unterbaum
      return ['SCRIPT', 'STYLE', 'NOSCRIPT'].includes(node.tagName)
        ? NodeFilter.FILTER_REJECT
        : NodeFilter.FILTER_SKIP; // Element selbst nicht liefern, Kinder aber prüfen
    }
    return /\S/.test(node.nodeValue)
      ? NodeFilter.FILTER_ACCEPT
      : NodeFilter.FILTER_SKIP;
  }
);

const visibleTexts = [];
while (walker.nextNode()) visibleTexts.push(walker.currentNode);
console.log(visibleTexts.length, 'sichtbare Textknoten');
57 sichtbare Textknoten

Suchbegriff hervorheben (erst sammeln, dann ändern)

const highlight = (root, term) => {
  const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
  const matches = [];
  while (walker.nextNode()) {
    if (walker.currentNode.nodeValue.includes(term)) matches.push(walker.currentNode);
  }
  // DOM erst nach dem Durchlauf verändern
  for (const textNode of matches) {
    const idx = textNode.nodeValue.indexOf(term);
    const hit = textNode.splitText(idx);
    hit.splitText(term.length);
    const mark = document.createElement('mark');
    hit.replaceWith(mark);
    mark.append(hit);
  }
  return matches.length;
};

console.log(highlight(document.querySelector('main'), 'JavaScript'));
4

Strukturell navigieren mit currentNode, parentNode() und Geschwistern

const list = document.querySelector('ul.menu');
const walker = document.createTreeWalker(list, NodeFilter.SHOW_ELEMENT);

walker.currentNode = list.querySelector('li.active');
const next = walker.nextSibling();      // nächstes <li> oder null
console.log(next?.textContent);

walker.currentNode = list.querySelector('li.active a');
console.log(walker.parentNode()?.tagName); // LI
console.log(walker.parentNode()?.tagName); // UL (root)
console.log(walker.parentNode());          // null – root ist die Grenze
Kontakt LI UL null

// Wichtig · Fallstricke

  • Der Wurzelknoten wird von nextNode() nicht geliefert: Der Walker startet auf root, und der erste Aufruf von nextNode() gibt bereits den nächsten Knoten zurück. Soll root selbst mitgeprüft werden, musst du das separat tun.
  • FILTER_REJECT und FILTER_SKIP sind nicht dasselbe: FILTER_REJECT schneidet beim TreeWalker den ganzen Unterbaum ab, FILTER_SKIP überspringt nur den einzelnen Knoten. Beim NodeIterator verhalten sich beide Werte gleich.
  • DOM während des Durchlaufs verändern: Wird currentNode entfernt, bleibt der Walker an einem losgelösten Knoten hängen, und nextNode() liefert dann oft null. Sammle die Knoten deshalb zuerst und verändere das DOM erst danach.
  • Du darfst currentNode auf jeden beliebigen Knoten setzen, auch auf einen außerhalb von root oder einen, den der Filter ablehnt. Danach navigiert der Walker aber unter Umständen unerwartet.
  • Die Filterfunktion wird synchron und für jeden Kandidaten aufgerufen. Halte sie deshalb schlank. Wirft sie eine Ausnahme, bricht die Navigation ab.
  • Shadow-DOM-Inhalte durchläuft der Walker nicht automatisch. Für einen Shadow-Baum brauchst du einen eigenen Walker mit dem shadowRoot als root.
  • Kompatibilität: Der TreeWalker wird von allen Browsern unterstützt, seit Internet Explorer 9. Der früher vorhandene vierte Parameter entityReferenceExpansion ist veraltet und wird ignoriert.