Técnicas de Manipulação do DOM em JavaScript
Aprenda técnicas de manipulação do DOM em JavaScript: crie, insira, substitua e remova elementos, e otimize com batching, fragmentos de documento e clonagem de nós para minimizar reflows.
A manipulação do DOM (Document Object Model) é um aspecto fundamental do desenvolvimento web que permite criar páginas dinâmicas e interativas ao modificar a estrutura, o conteúdo e o estilo do documento a partir do JavaScript. Este guia começa com as técnicas essenciais para criar, inserir, substituir e remover elementos, e depois avança para boas práticas e otimizações de desempenho — batching, fragmentos de documento e clonagem de nós — que mantêm essas alterações rápidas.
Se você ainda não selecionou um elemento, comece com seleção de elementos do DOM. Para entender a árvore que você está modificando, consulte compreendendo os nós do DOM.
Técnicas Essenciais de Manipulação
Toda alteração no DOM se enquadra em uma de quatro categorias: criar nós, inseri-los, substituí-los ou removê-los.
Criando Elementos
Use document.createElement() para construir um elemento na memória, defina seu conteúdo e atributos antes de inseri-lo na página. Um nó criado não é visível até que seja anexado ao documento.
const card = document.createElement('div');
card.className = 'card';
card.textContent = 'Hello, DOM!';
card.setAttribute('data-role', 'greeting');
console.log(card.outerHTML);
// <div class="card" data-role="greeting">Hello, DOM!</div>Prefira textContent em vez de innerHTML ao inserir texto simples — é mais rápido e evita o risco de segurança de injeção de HTML não escapado.
Inserindo Elementos
Uma vez que o elemento existe, anexe-o com um destes métodos:
parent.append(node)— adiciona o nó como último filho (também aceita strings simples).parent.prepend(node)— adiciona como primeiro filho.target.before(node)/target.after(node)— insere um irmão antes ou depois detarget.parent.appendChild(node)— a API clássica; anexa um único nó e o retorna.parent.insertBefore(node, reference)— inserenodeantes do filhoreference.
const list = document.createElement('ul');
const first = document.createElement('li');
first.textContent = 'First';
list.append(first);
const second = document.createElement('li');
second.textContent = 'Second';
list.append(second);
// Put a new item before the first one.
const top = document.createElement('li');
top.textContent = 'Top';
first.before(top);
console.log(list.children.length); // 3
console.log(list.firstElementChild.textContent); // TopPara inserir uma string HTML em uma posição precisa sem reanalisar o elemento pai inteiro, use insertAdjacentHTML():
const wrapper = document.createElement('div');
const box = document.createElement('div');
box.textContent = 'middle';
wrapper.append(box); // box must be in the tree to gain siblings
box.insertAdjacentHTML('beforebegin', '<span>before</span>');
box.insertAdjacentHTML('afterend', '<span>after</span>');
console.log(box.previousElementSibling.textContent); // before
console.log(box.nextElementSibling.textContent); // afterSubstituindo e Removendo Elementos
oldNode.replaceWith(newNode)— substituioldNodepornewNodeno lugar.element.remove()— desconecta o elemento do DOM.parent.replaceChild(newNode, oldNode)eparent.removeChild(child)— os equivalentes mais antigos.
const parent = document.createElement('div');
const a = document.createElement('p');
a.textContent = 'old';
parent.append(a);
const b = document.createElement('p');
b.textContent = 'new';
a.replaceWith(b);
console.log(parent.innerHTML); // <p>new</p>
b.remove();
console.log(parent.innerHTML); // (empty)Os métodos modernos (append, prepend, before, after, replaceWith, remove) são mais fáceis de ler do que os legados appendChild/insertBefore/replaceChild/removeChild e aceitam múltiplos nós e strings de uma só vez. Prefira-os; recorra à API legada apenas quando for necessário suportar navegadores muito antigos.
Boas Práticas de Manipulação do DOM
Minimize o Acesso Direto ao DOM
Acessar o DOM pode ser lento porque pode fazer o navegador recalcular o layout e repintar os elementos. Para minimizar o acesso direto ao DOM:
- Agrupe as atualizações do DOM em lote em vez de realizar múltiplas atualizações pequenas.
- Use variáveis para armazenar referências a elementos acessados com frequência.
Otimize o Tratamento de Eventos
Anexe manipuladores de eventos de forma eficiente:
- Use delegação de eventos para reduzir o número de ouvintes de eventos.
- Evite anexar muitos ouvintes de eventos diretamente aos elementos.
Limpe Elementos Desnecessários
Remova elementos que não são mais necessários para liberar memória e melhorar o desempenho:
- Use os métodos
removeChildouremovepara excluir elementos do DOM.
Minimizando Reflows e Repaints
O que São Reflows e Repaints?
- Reflows ocorrem quando o layout de uma parte da página muda, fazendo o navegador recalcular as posições e tamanhos dos elementos.
- Repaints acontecem quando a aparência visual dos elementos muda sem afetar o layout (por exemplo, mudanças de cor).
Técnicas para Minimizar Reflows e Repaints
Agrupar Alterações em Lote
Agrupe múltiplas alterações para evitar reflows e repaints repetidos:
<!DOCTYPE html>
<html>
<head>
<title>Batching Changes</title>
</head>
<body>
<div id="content">Original Content</div>
<button id="update">Update Content</button>
<script>
document.getElementById('update').addEventListener('click', () => {
const content = document.getElementById('content');
content.style.display = 'none'; // Hide element to batch changes
content.innerHTML = 'Updated Content';
content.style.display = 'block'; // Show element after updates
});
</script>
</body>
</html>Este exemplo mostra como agrupar alterações em um elemento do DOM para minimizar reflows e repaints. Ao ocultar o elemento antes de realizar múltiplas atualizações e exibi-lo novamente depois, você evita reflows e repaints intermediários.
Use Classes CSS para Alterações
Aplique alterações de CSS usando classes em vez de manipular estilos diretamente:
<!DOCTYPE html>
<html>
<head>
<title>Use CSS Classes</title>
<style>
.hidden { display: none; }
.highlight { color: red; font-weight: bold; }
</style>
</head>
<body>
<div id="content">Hello World</div>
<button id="toggle">Toggle Highlight</button>
<script>
document.getElementById('toggle').addEventListener('click', () => {
const content = document.getElementById('content');
content.classList.toggle('highlight');
});
</script>
</body>
</html>Este exemplo demonstra como usar classes CSS para aplicar múltiplas alterações de estilo de uma só vez, o que é mais eficiente do que modificar propriedades de estilo individualmente. Alternar uma classe que muda múltiplos estilos ajuda a reduzir o número de reflows e repaints.
Usando Fragmentos de Documento para Desempenho
O que É um Fragmento de Documento?
Um Fragmento de Documento é um contêiner leve usado para armazenar um grupo de nós. Ele não faz parte da árvore principal do DOM, o que significa que as alterações nele não acionam reflows e repaints.
Ao realizar múltiplas manipulações no DOM, use DocumentFragment para agrupar suas alterações e anexá-las ao DOM em uma única operação. Essa abordagem minimiza reflows e repaints, melhorando significativamente o desempenho.
Exemplo de Uso de Fragmentos de Documento
<!DOCTYPE html>
<html>
<head>
<title>Document Fragments</title>
</head>
<body>
<div id="list"></div>
<button id="populate">Populate List</button>
<script>
document.getElementById('populate').addEventListener('click', (event) => {
const fragment = document.createDocumentFragment();
for (let i = 1; i <= 25; i++) {
const item = document.createElement('div');
item.textContent = `Item ${i}`;
fragment.appendChild(item);
}
document.getElementById('list').appendChild(fragment);
event.target.disabled = true; // Disable the button
});
</script>
</body>
</html>Este exemplo cria 25 elementos div e os adiciona a um Fragmento de Documento. Somente após todos os elementos serem adicionados ao fragmento, o fragmento é inserido no DOM em uma única operação. Essa abordagem minimiza reflows e repaints ao atualizar o DOM apenas uma vez.
Clonando Nós
O Método cloneNode()
O método cloneNode() é usado para criar uma cópia de um nó. Ele pode clonar o próprio nó ou o nó junto com seus filhos.
Clonando um Nó Sem Filhos
<!DOCTYPE html>
<html>
<head>
<title>Cloning Nodes</title>
</head>
<body>
<div id="original">Original Node</div>
<button id="clone">Clone Node</button>
<script>
document.getElementById('clone').addEventListener('click', () => {
const original = document.getElementById('original');
const clone = original.cloneNode(false); // Clone without children
clone.id = 'clone';
clone.textContent = 'Cloned Node';
document.body.appendChild(clone);
});
</script>
</body>
</html>Este exemplo demonstra como clonar um nó sem seus filhos usando o método cloneNode(false). O nó clonado copiará os atributos e o conteúdo de texto do nó original, mas não seus nós filhos.
Clonando um Nó Com Filhos
<!DOCTYPE html>
<html>
<head>
<title>Cloning Nodes with Children</title>
</head>
<body>
<div id="original">
Original Node
<span>Child Node</span>
</div>
<button id="clone">Clone Node with Children</button>
<script>
document.getElementById('clone').addEventListener('click', () => {
const original = document.getElementById('original');
const clone = original.cloneNode(true); // Clone with children
clone.id = 'clone';
document.body.appendChild(clone);
});
</script>
</body>
</html>Este exemplo demonstra como clonar um nó junto com seus filhos usando o método cloneNode(true). O nó clonado incluirá o conteúdo do nó original e todos os seus nós descendentes.
Conclusão
A manipulação eficiente do DOM é fundamental para criar aplicações web com bom desempenho. Comece dominando os métodos essenciais para criar, inserir, substituir e remover elementos, e depois adicione as otimizações: agrupe suas atualizações em lote, prefira classes CSS a estilos inline, use DocumentFragment para inserções em massa e clone nós quando precisar de estruturas repetidas. Em conjunto, essas técnicas mantêm suas páginas responsivas mesmo conforme o DOM cresce.
Tópicos Relacionados
- Manipulação do DOM — um guia mais amplo sobre leitura e escrita na árvore do documento.
- Percorrendo o DOM — navegue entre pais, filhos e irmãos.
- Otimização de Desempenho do DOM — aprofunde-se em manter a manipulação rápida.
- Tratamento de Eventos no DOM — conecte interações de forma eficiente.