TreeWalker — последовательный обход DOM без создания промежуточной коллекции!
При обходе DOM часто используют рекурсию или querySelectorAll(). Это рабочие подходы, но они подходят не для всех задач: рекурсивный обход требует дополнительной логики, а querySelectorAll() сразу формирует статический NodeList со всеми найденными элементами.
DOM API предоставляет интерфейс TreeWalker, который позволяет последовательно обходить дерево документа и получать только нужные узлы по мере обхода. Например, создадим объект для обхода элементов:
{
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT
);
let node;
while ((node = walker.nextNode())) {
console.log(node.tagName);
}
}
Обход начинается с потомков переданного корневого узла, поэтому сам document.body в цикл не попадёт.
TreeWalker поддерживает фильтрацию узлов. Например, можно возвращать только кнопки во время обхода дерева:
{
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT,
{
acceptNode(node) {
return node.tagName === 'BUTTON'
? NodeFilter.FILTER_ACCEPT
: NodeFilter.FILTER_SKIP;
}
}
);
let node;
while ((node = walker.nextNode())) {
console.log(node);
}
}
Фильтр вызывается для узлов во время обхода, поэтому отдельная коллекция найденных элементов не создаётся.
FILTER_SKIP пропускает текущий узел, но продолжает обход его потомков. Если необходимо исключить всё поддерево целиком, используется FILTER_REJECT. TreeWalker также поддерживает навигацию в разных направлениях:
walker.parentNode();
walker.firstChild();
walker.lastChild();
walker.previousSibling();
walker.nextSibling();
walker.previousNode();
walker.nextNode();
Например, можно найти первый элемент с атрибутом data-error и сразу прокрутить страницу к нему:
{
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT
);
let node;
while ((node = walker.nextNode())) {
if (node.hasAttribute('data-error')) {
node.scrollIntoView({
behavior: 'smooth',
block: 'center'
});
break;
}
}
}
В отличие от querySelectorAll(), TreeWalker не создаёт промежуточную коллекцию найденных элементов, а возвращает узлы по мере обхода дерева.
При этом TreeWalker не обязательно будет быстрее querySelectorAll() в каждом конкретном случае. Выбор зависит от задачи: для простого поиска по CSS-селектору обычно удобнее querySelector() или querySelectorAll(), а для управляемого последовательного обхода дерева — TreeWalker.
🔥 TreeWalker определён в DOM Standard и предоставляет низкоуровневый механизм навигации по DOM с возможностью фильтрации узлов во время обхода. Он подходит для реализации редакторов, инструментов анализа DOM и библиотек, которым требуется последовательный обход дерева с полным контролем над процессом навигации.
📣 Code Ready | #практика
При обходе DOM часто используют рекурсию или querySelectorAll(). Это рабочие подходы, но они подходят не для всех задач: рекурсивный обход требует дополнительной логики, а querySelectorAll() сразу формирует статический NodeList со всеми найденными элементами.
DOM API предоставляет интерфейс TreeWalker, который позволяет последовательно обходить дерево документа и получать только нужные узлы по мере обхода. Например, создадим объект для обхода элементов:
{
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT
);
let node;
while ((node = walker.nextNode())) {
console.log(node.tagName);
}
}
Обход начинается с потомков переданного корневого узла, поэтому сам document.body в цикл не попадёт.
TreeWalker поддерживает фильтрацию узлов. Например, можно возвращать только кнопки во время обхода дерева:
{
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT,
{
acceptNode(node) {
return node.tagName === 'BUTTON'
? NodeFilter.FILTER_ACCEPT
: NodeFilter.FILTER_SKIP;
}
}
);
let node;
while ((node = walker.nextNode())) {
console.log(node);
}
}
Фильтр вызывается для узлов во время обхода, поэтому отдельная коллекция найденных элементов не создаётся.
FILTER_SKIP пропускает текущий узел, но продолжает обход его потомков. Если необходимо исключить всё поддерево целиком, используется FILTER_REJECT. TreeWalker также поддерживает навигацию в разных направлениях:
walker.parentNode();
walker.firstChild();
walker.lastChild();
walker.previousSibling();
walker.nextSibling();
walker.previousNode();
walker.nextNode();
Например, можно найти первый элемент с атрибутом data-error и сразу прокрутить страницу к нему:
{
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT
);
let node;
while ((node = walker.nextNode())) {
if (node.hasAttribute('data-error')) {
node.scrollIntoView({
behavior: 'smooth',
block: 'center'
});
break;
}
}
}
В отличие от querySelectorAll(), TreeWalker не создаёт промежуточную коллекцию найденных элементов, а возвращает узлы по мере обхода дерева.
При этом TreeWalker не обязательно будет быстрее querySelectorAll() в каждом конкретном случае. Выбор зависит от задачи: для простого поиска по CSS-селектору обычно удобнее querySelector() или querySelectorAll(), а для управляемого последовательного обхода дерева — TreeWalker.
🔥 TreeWalker определён в DOM Standard и предоставляет низкоуровневый механизм навигации по DOM с возможностью фильтрации узлов во время обхода. Он подходит для реализации редакторов, инструментов анализа DOM и библиотек, которым требуется последовательный обход дерева с полным контролем над процессом навигации.
📣 Code Ready | #практика