Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Як працює MutationObserver?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`MutationObserver`** - це вбудований API, який асинхронно спостерігає за елементом і викликає колбек, коли в ньому змінюються структура (`childList`), атрибути (`attributes`) або текст (`characterData`). **Ключове:** він не блокує інтерфейс, доставляє зміни пакетами через чергу мікротасків і керується методами `observe()`, `disconnect()` та `takeRecords()`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення`MutationObserver` - це вбудований у браузер API, який дозволяє **стежити за змінами в DOM**: додаванням, видаленням, зміною атрибутів або тексту елементів, і реагувати на це в реальному часі. Це потужна альтернатива старим подіям на кшталт `DOMSubtreeModified` (які застаріли й гальмували сторінку). --- ## Визначення > `MutationObserver` - це спеціальний об'єкт, який "спостерігає" за елементом і повідомляє, коли в ньому **щось змінилося** (структура, атрибути, текст тощо). Він працює **асинхронно**, не блокує інтерфейс і викликає колбек, коли у спостережуваному вузлі відбулися зміни. --- ## 1. Базовий приклад ```javascript // Створюємо спостерігач const observer = new MutationObserver((mutations) => { mutations.forEach(mutation => { console.log('Тип зміни:', mutation.type); }); }); // Елемент, за яким будемо стежити const target = document.querySelector('#app'); // Налаштування спостереження observer.observe(target, { childList: true, // стежити за додаванням/видаленням дочірніх елементів attributes: true, // стежити за зміною атрибутів subtree: true // стежити за всім усередині елемента }); ``` Тепер, якщо ти додаси в `#app` новий елемент або зміниш атрибут, у консолі з'явиться повідомлення про тип зміни. --- ## 2. Приклад роботи "наживо" ```javascript <div id="box">Привіт!</div> <button id="btn">Змінити</button> <script> const box = document.getElementById('box'); const btn = document.getElementById('btn'); const observer = new MutationObserver((mutations) => { mutations.forEach(m => console.log(m)); }); observer.observe(box, { childList: true, attributes: true, characterData: true }); btn.addEventListener('click', () => { box.textContent = 'Текст змінено!'; box.setAttribute('data-status', 'updated'); }); </script> ``` При кліку в консолі з'являться об'єкти `MutationRecord`, у яких буде інформація про: - тип зміни (`attributes`, `childList`, `characterData`); - який атрибут змінився; - старе і нове значення (якщо ввімкнено). --- ## 3. Налаштування observe() ```javascript observer.observe(target, { childList: true, // додавання/видалення дочірніх елементів attributes: true, // зміна атрибутів characterData: true, // зміна тексту всередині вузлів subtree: true, // стежити за нащадками (усе дерево) attributeFilter: ['class', 'style'], // стежити лише за цими атрибутами attributeOldValue: true, // зберігати старе значення атрибутів characterDataOldValue: true // зберігати старе значення тексту }); ``` --- ## 4. Що містить MutationRecord Кожен елемент масиву `mutations` - це об'єкт `MutationRecord` із властивостями: | Властивість | Опис | |---|---| | `type` | тип зміни (`attributes`, `childList`, `characterData`) | | `target` | елемент, де відбулася зміна | | `addedNodes` | додані елементи | | `removedNodes` | видалені елементи | | `attributeName` | ім'я зміненого атрибута | | `oldValue` | старе значення атрибута або тексту | --- ## 5. Зупинка спостереження Щоб перестати стежити: ```javascript observer.disconnect(); ``` Щоб тимчасово призупинити і знову ввімкнути: ```javascript observer.takeRecords(); // повертає накопичені зміни observer.observe(...); // можна ввімкнути знову ``` --- ## 6. Приклад: стежимо за динамічними вставками Дуже поширений кейс - ловити нові елементи, додані JS-фреймворком (наприклад, React, Vue, або чужим скриптом): ```javascript const container = document.querySelector('#feed'); const observer = new MutationObserver((mutations) => { mutations.forEach(m => { m.addedNodes.forEach(node => { if (node.nodeType === 1 && node.matches('.post')) { console.log('Новий пост додано:', node.textContent); } }); }); }); observer.observe(container, { childList: true, subtree: true }); ``` Тепер при динамічному додаванні `<div class="post">...</div>` JS миттєво відреагує. --- ## 7. Приклад: автоматична реакція на зміну класу ```javascript const box = document.querySelector('#box'); const observer = new MutationObserver((entries) => { for (const mutation of entries) { if (mutation.attributeName === 'class') { console.log('Клас змінився на:', box.className); } } }); observer.observe(box, { attributes: true }); ``` Це зручно для відстеження зміни стану, наприклад під час анімацій або toggle-ефектів. --- ## 8. Продуктивність - `MutationObserver` працює **асинхронно**: зміни "пакуються" і приходять одним батчем, а не на кожен піксель чи символ. - Це робить його **дуже продуктивним** навіть за великої кількості спостережень. - Але не зловживай `subtree: true` на всьому `document` - це може бути дорого. --- ## Підсумок | Що робить | `MutationObserver` | |---|---| | Відстежує | Зміни в DOM (атрибути, текст, додавання/видалення елементів) | | Заміна для | Старих подій `DOMNodeInserted`, `DOMSubtreeModified` | | Працює | Асинхронно, через чергу мікротасків | | Використовується для | Динамічного UI, інтеграцій, спостереження за React/Vue, анімацій, кастомних компонентів | | Керування | `observe()`, `disconnect()`, `takeRecords()` | --- > **Запам'ятай просто:** > `MutationObserver` - це "охоронець DOM": стежить за змінами в дереві й повідомляє, що, де і коли змінилося, без постійних перевірок чи подій `scroll`.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.