В этом руководстве вы узнаете, как использовать 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 и выполняет обратный вызов каждый раз, когда происходит изменение.
