Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як стежити за змінами DOM через MutationObserver?

MutationObserver повідомляє про зміни в DOM: додавання й видалення вузлів, зміну атрибутів чи тексту. Він замінив застарілі й повільні mutation events (DOMNodeInserted), які браузери поступово видаляють (Chrome - з версії 127).

const observer = new MutationObserver((mutations) => {
  for (const mutation of mutations) {
    for (const node of mutation.addedNodes) {
      if (node instanceof Element) {
        node.querySelectorAll('[data-tooltip]').forEach(initTooltip);
        if (node.matches('[data-tooltip]')) initTooltip(node);
      }
    }
  }
});

observer.observe(document.body, { childList: true, subtree: true });

Що можна спостерігати (опції observe):

  • childList - додавання й видалення дочірніх вузлів;
  • subtree - разом з усіма нащадками, а не лише прямими дітьми;
  • attributes (+ attributeFilter: ['class', 'disabled'], attributeOldValue) - зміни атрибутів;
  • characterData - зміни тексту у текстових вузлах.

Як він виконується. Колбек викликається асинхронно, пакетом, як мікрозадача після поточного коду. Сто змін в одному циклі - один виклик з масивом записів. Тому він значно дешевший за старі синхронні події.

Де корисний:

  • ініціалізація сторонніх віджетів на вмісті, що з'являється динамічно (підвантаження, Livewire-оновлення, wire:navigate);
  • реакція на зміни, які робить чужий код, якого ви не контролюєте;
  • автоматичні тести й інструменти доступності, що стежать за змінами сторінки.

Підводні камені:

  • subtree: true на document.body - колбек на кожну зміну всієї сторінки. На складних сторінках це відчутно. Спостерігати варто найменший можливий контейнер з мінімумом опцій;
  • нескінченний цикл: колбек змінює DOM у тій самій області - це породжує нові записи. Потрібна перевірка, чи елемент уже оброблено (наприклад, атрибут-позначка);
  • відключення: observer.disconnect() при знищенні компонента, інакше спостерігач триматиме посилання на вузли. takeRecords() дає змогу забрати ще не доставлені записи перед відключенням;
  • не для розміру й видимості: для них є ResizeObserver і IntersectionObserver - зміна розміру не є мутацією DOM.

Альтернатива, якщо ви контролюєте код, що змінює DOM, - викликати ініціалізацію явно чи через власну подію. Спостерігач потрібен саме тоді, коли зміни відбуваються «десь» поза вашим контролем.

Livewire і Alpine самі використовують MutationObserver: Alpine так помічає нові елементи з x-data і ініціалізує їх.

Докладніше в документації: MutationObserver

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання