Signatur
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}`);
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');
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'));
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
// Wichtig · Fallstricke
- Der Wurzelknoten wird von
nextNode()nicht geliefert: Der Walker startet aufroot, und der erste Aufruf vonnextNode()gibt bereits den nächsten Knoten zurück. Sollrootselbst mitgeprüft werden, musst du das separat tun. FILTER_REJECTundFILTER_SKIPsind nicht dasselbe:FILTER_REJECTschneidet beimTreeWalkerden ganzen Unterbaum ab,FILTER_SKIPüberspringt nur den einzelnen Knoten. BeimNodeIteratorverhalten sich beide Werte gleich.- DOM während des Durchlaufs verändern: Wird
currentNodeentfernt, bleibt der Walker an einem losgelösten Knoten hängen, undnextNode()liefert dann oftnull. Sammle die Knoten deshalb zuerst und verändere das DOM erst danach. - Du darfst
currentNodeauf jeden beliebigen Knoten setzen, auch auf einen außerhalb vonrootoder 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
shadowRootalsroot. - Kompatibilität: Der
TreeWalkerwird von allen Browsern unterstützt, seit Internet Explorer 9. Der früher vorhandene vierte ParameterentityReferenceExpansionist veraltet und wird ignoriert.