В этом руководстве вы узнаете, как использовать JavaScript MutationObserver
API для отслеживания изменений, вносимых в дерево DOM.
API MutationObserver
позволяет отслеживать изменения, вносимые в дерево DOM. Когда узлы DOM изменяются, вы можете вызвать функцию обратного вызова, чтобы отреагировать на изменения.
Основные шаги для использования MutationObserver
API:
- Во-первых, определите функцию обратного вызова, которая будет выполняться при изменении DOM:
function callback(mutations) { // }
- Во-вторых, создайте объект
MutationObserver
и передайте обратный вызов конструкторуMutationObserver()
:
let observer = new MutationObserver(callback);
- В-третьих, вызовите метод
observe()
, чтобы начать наблюдение за изменениями DOM.
observer.observe(targetNode, observerOptions);
Метод observe()
имеет два параметра. target
является корнем поддерева узлов для отслеживания изменений. Параметр ObserverOptions содержит свойства, которые указывают, какие изменения DOM должны передаваться в обратный вызов observerOptions
.
Наконец, закончите наблюдать за изменениями DOM, вызвав метод disconnect()
:
observer.disconnect();
Опции
Второй аргумент observe()
позволяет указать параметры для описания MutationObserver
:
let options = { childList: true, attributes: true, characterData: false, subtree: false, attributeFilter: ['attr1', 'attr2'], attributeOldValue: false, characterDataOldValue: false };
Вам не нужно использовать все варианты. Однако, чтобы MutationObserver
работал, по крайней мере один из childList
, attributes
или characterData
должен быть установлен в true
, иначе методObserver observer()
выдаст ошибку.
Наблюдение за изменениями в дочерних элементах
Предположим, что у вас есть следующий список:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>MutationObserver Demo: ChildList</title> </head> <body> <ul id="language"> <li>HTML</li> <li>CSS</li> <li>JavaScript</li> <li>TypeScript</li> </ul> <button id="btnStart">Start Observing</button> <button id="btnStop">Stop Observing</button> <button id="btnAdd">Add</button> <button id="btnRemove">Remove the Last Child</button> <script src="app.js"></script> </body> </html>
В следующем примере показано, как использовать свойство childList
объекта options
мутации для отслеживания изменений дочернего узла.
- Сначала выберите такие элементы, как
list
иbuttons
, используя методquerySelector()
. По умолчанию кнопка «Stop Observing
»disabled
.
// selecting list let list = document.querySelector('#language'); // selecting buttons let btnAdd = document.querySelector('#btnAdd'); let btnRemove = document.querySelector('#btnRemove'); let btnStart = document.querySelector('#btnStart'); let btnStop = document.querySelector('#btnStop'); btnStop.disabled = true;
- Во-вторых, объявите функцию
log()
, которая будет использоваться в качестве обратного вызова дляMutationObserver
:
function log(mutations) { for(let mutation of mutations) { if(mutation.type === 'childList') { console.log(mutation); } } }
- В-третьих, создайте новый объект:
let observer = new MutationObserver(log);
- В-четвертых, начните наблюдать за изменениями DOM в дочерних узлах элемента списка, когда нажата кнопка «
Start Observing
», вызвав методobserve()
сchildList
объектаoptions
, установленным в значениеtrue
:
btnStart.addEventListener('click', function() { observer.observe(list, { childList: true }); btnStart.disabled = true; btnStop.disabled = false; });
- В-пятых, добавьте новый элемент списка при нажатии кнопки
add
:
let counter = 1; btnAdd.addEventListener('click', function() { // create a new item element let item = document.createElement('li'); item.textContent = `Item ${counter++}`; // append it to the child nodes of list list.appendChild(item); });
- В-шестых, удалите последний дочерний элемент
list
при нажатии кнопки «Remove
»:
btnRemove.addEventListener('click', function() { list.lastElementChild ? list.removeChild(list.lastElementChild) : console.log('No more child node to remove'); });
- Наконец, прекратите наблюдение за изменениями DOM при нажатии кнопки «
Stop Observing
», вызвав методdisconnect()
объектаMutationObserver
:
btnStop.addEventListener('click', function() { observer.disconnect(); // set button states btnStart.disabled = false; btnStop.disabled = true; });
Соединим все это вместе:
(function() { // selecting the list let list = document.querySelector('#language'); // selecting the buttons let btnAdd = document.querySelector('#btnAdd'); let btnRemove = document.querySelector('#btnRemove'); let btnStart = document.querySelector('#btnStart'); // disable the stop button let btnStop = document.querySelector('#btnStop'); btnStop.disabled = true; function log(mutations) { for(let mutation of mutations) { if(mutation.type === 'childList') { console.log(mutation); } } } let observer = new MutationObserver(log); btnStart.addEventListener('click', function() { observer.observe(list, { childList: true }); btnStart.disabled = true; btnStop.disabled = false; }); btnStop.addEventListener('click', function() { observer.disconnect(); // Set the button state btnStart.disabled = false; btnStop.disabled = true; }); let counter = 1; btnAdd.addEventListener('click', function() { // create a new item element let item = document.createElement('li'); item.textContent = `Item ${counter++}`; // append it to the child nodes of list list.appendChild(item); }); btnRemove.addEventListener('click', function() { list.lastElementChild ? list.removeChild(list.lastElementChild) : console.log('No more child node to remove'); }); })();
Обратите внимание, что мы поместили весь код в IIFE (выражение немедленно вызываемой функции).
Наблюдение за изменениями атрибутов
Чтобы наблюдать за изменениями атрибутов, вы используете следующее свойство attributes
объекта options
:
let options = { attributes: true }
Если вы хотите наблюдать за изменениями одного или нескольких определенных attributes
, игнорируя другие, вы можете использовать свойство attributeFilter
:
let options = { attributes: true, attributeFilter: ['class', 'style'] }
В этом примере MutationObserver
будет вызывать обратный вызов каждый раз, когда изменяется атрибут class
или style
.
Изменения в поддереве
Чтобы отслеживать целевой узел и его поддерево узлов, вы устанавливаете для свойства subtree
объекта options
значение true
:
let options = { subtree: true }
character data
Чтобы отслеживать изменения текстового содержимого узла, вы устанавливаете для свойства characterData
объекта options
значение true
:
let options = { characterData: true }
Доступ к старым значениям
Чтобы получить доступ к старым значениям атрибутов, вы устанавливаете для свойства attributeOldValue
объекта options
значение true
:
let options = { attributes: true, attributeOldValue: true }
Точно так же вы можете получить доступ к старому значению символьных данных, установив для свойства characterDataOldValue
объекта options
значение true
:
let options = { characterData: true, subtree: true, characterDataOldValue: true }
В этом руководстве вы узнали об API JavaScript MutationObserver
, который отслеживает изменения DOM и выполняет обратный вызов каждый раз, когда происходит изменение.