Resumo : neste tutorial, você aprenderá como usar a MutationObserver
API JavaScript para observar as alterações feitas na árvore DOM.
Introdução à API JavaScript MutationObserver
A MutationObserver
API permite monitorar as alterações feitas na árvore DOM. Quando os nós DOM mudam, você pode invocar uma função de retorno de chamada para reagir às mudanças.
As etapas básicas para usar a MutationObserver
API são:
Primeiro, defina a função de retorno de chamada que será executada quando o DOM mudar:
function callback(mutations) {
//
}
Linguagem de código: JavaScript ( javascript )
Segundo, crie um MutationObserver
objeto e passe o retorno de chamada para o MutationObserver()
construtor:
let observer = new MutationObserver(callback);
Linguagem de código: JavaScript ( javascript )
Terceiro, chame o observe()
método para começar a observar as alterações do DOM.
observer.observe(targetNode, observerOptions);
Linguagem de código: JavaScript ( javascript )
O observe()
método possui dois parâmetros. A target
é a raiz da subárvore de nós para monitorar alterações. O observerOptions
parâmetro contém propriedades que especificam quais alterações no DOM devem ser relatadas ao retorno de chamada do observador.
Por fim, pare de observar as alterações do DOM chamando o disconnect()
método:
observer.disconnect();
Linguagem de código: JavaScript ( javascript )
As opções do MutationObserver
O segundo argumento do observe()
método permite especificar opções para descrever MutationObserver
:
let options = {
childList: true,
attributes: true,
characterData: false,
subtree: false,
attributeFilter: ['attr1', 'attr2'],
attributeOldValue: false,
characterDataOldValue: false
};
Linguagem de código: JavaScript ( javascript )
Você não precisa usar todas as opções. No entanto, para funcionar MutationObserver
, pelo menos um de childList
, attributes
ou characterData
precisa ser definido como true
, caso contrário, o observer()
método gerará um erro.
Observando mudanças em elementos filhos
Supondo que você tenha a seguinte lista:
<!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>
Linguagem de código: HTML, XML ( xml )
O exemplo a seguir ilustra como usar a childList
propriedade do options
objeto de mutação para monitorar as alterações do nó filho.
Primeiro, selecione os elementos como list
e buttons
usando o querySelector()
método. Por padrão, o Stop Observing
botão é 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;
Linguagem de código: JavaScript ( javascript )
Segundo, declare uma log()
função que será usada como retorno de chamada para MutationObserver
:
function log(mutations) {
for (let mutation of mutations) {
if (mutation.type === 'childList') {
console.log(mutation);
}
}
}
Linguagem de código: JavaScript ( javascript )
Terceiro, crie um novo MutationObserver
objeto:
let observer = new MutationObserver(log);
Linguagem de código: JavaScript ( javascript )
Quarto, comece a observar as alterações do DOM nos nós filhos do elemento da lista quando o Start Observing
botão é clicado, chamando o observe()
método com o childList
do options
objeto definido como true
:
btnStart.addEventListener('click', function () {
observer.observe(list, {
childList: true
});
btnStart.disabled = true;
btnStop.disabled = false;
});
Linguagem de código: JavaScript ( javascript )
Quinto, adicione um novo item de lista quando o add
botão for clicado:
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);
});
Linguagem de código: JavaScript ( javascript )
Sexto, remova o último filho de list
quando o Remove
botão for clicado:
btnRemove.addEventListener('click', function () {
list.lastElementChild ?
list.removeChild(list.lastElementChild) :
console.log('No more child node to remove');
});
Linguagem de código: JavaScript ( javascript )
Por fim, pare de observar as alterações do DOM quando o Stop Observing
botão é clicado, chamando o disconnect()
método do MutationObserver
objeto:
btnStop.addEventListener('click', function () {
observer.disconnect();
// set button states
btnStart.disabled = false;
btnStop.disabled = true;
});
Linguagem de código: JavaScript ( javascript )
Junte tudo:
(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');
});
})();
Linguagem de código: JavaScript ( javascript )
Observe que colocamos todo o código em um IIFE (Immediately Invoked Function Expression).
Observando mudanças nos atributos
Para observar alterações nos atributos, você usa a seguinte attributes
propriedade do options
objeto:
let options = {
attributes: true
}
Linguagem de código: JavaScript ( javascript )
Se quiser observar as alterações em um ou mais específicos attributes
enquanto ignora os outros, você pode usar a attributeFilter
propriedade:
let options = {
attributes: true,
attributeFilter: ['class', 'style']
}
Linguagem de código: JavaScript ( javascript )
Neste exemplo, o MutationObserver
irá invocar o retorno de chamada sempre que o atributo class
ou style
for alterado.
Observando mudanças em uma subárvore
Para monitorar o nó de destino e sua subárvore de nós, defina a subtree
propriedade do options
objeto como true
:
let options = {
subtree: true
}
Linguagem de código: JavaScript ( javascript )
Observando alterações nos dados do personagem
Para monitorar o nó em busca de alterações em seu conteúdo textual, defina a characterData
propriedade do options
objeto como true
:
let options = {
characterData: true
}
Linguagem de código: JavaScript ( javascript )
Acessando valores antigos
Para acessar os valores antigos dos atributos, você define a attributeOldValue
propriedade do options
objeto como true
:
let options = {
attributes: true,
attributeOldValue: true
}
Linguagem de código: JavaScript ( javascript )
Da mesma forma, você pode acessar o valor antigo dos dados do caractere definindo a characterDataOldValue
propriedade do options
objeto como true
:
let options = {
characterData: true,
subtree: true,
characterDataOldValue: true
}
Linguagem de código: JavaScript ( javascript )
Um exemplo prático de MutationObserver
Em aplicativos JavaScript, os elementos da página normalmente são gerados dinamicamente. Para esperar por um elemento dinâmico, você precisa usar MutationObserver
.
A waitForElement()
função a seguir espera por um ou mais elementos especificados por um seletor usando MutationObserver
.
function waitForElement(selector) {
return new Promise((resolve) => {
if (document.querySelector(selector)) {
return resolve(element);
}
const observer = new MutationObserver(() => {
const element = document.querySelector(selector);
if (element) {
resolve(element);
observer.disconnect();
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
});
}
Linguagem de código: JavaScript ( javascript )
Como funciona.
A waitForElement()
função retorna uma promessa. A promessa será resolvida assim que o elemento estiver disponível.
Primeiro, resolva o elemento se estiver disponível:
if (document.querySelector(selector)) {
return resolve(element);
}
Linguagem de código: JavaScript ( javascript )
Segundo, crie um novo MutationObserver
objeto para observar a árvore DOM se o elemento não estiver disponível:
const observer = new MutationObserver(() => {
const element = document.querySelector(selector);
if (element) {
resolve(element);
observer.disconnect();
}
});
Linguagem de código: JavaScript ( javascript )
O objeto observador chamará a função resolve() assim que o elemento estiver disponível e parará de observar a árvore DOM.
Terceiro, observe os elementos de toda a árvore DOM:
observer.observe(document.body, {
childList: true,
subtree: true,
});
Linguagem de código: CSS ( css )
Como waitForElement()
retorna a Promise
, você pode usar o then()
método assim:
waitForElement()('.a-class').then((element) => {
console.log('Element is ready');
console.log(element.textContent);
});
Linguagem de código: JavaScript ( javascript )
Ou você pode usar await
a sintaxe:
const element = await waitForElement()('.a-class');
console.log(element.textContent);
Linguagem de código: JavaScript ( javascript )
Neste tutorial, você aprendeu sobre a MutationObserver
API JavaScript que monitora as alterações do DOM e executa um retorno de chamada sempre que a alteração ocorre.