DOM: criando, modificando e removendo elementos
1. Introdução à Manipulação do DOM
O DOM (Document Object Model) é a representação em árvore de uma página HTML que o navegador constrói ao carregar um documento. Manipular o DOM significa criar, alterar ou remover nós dessa árvore em tempo real, permitindo que interfaces web sejam dinâmicas e responsivas à interação do usuário.
A manipulação do DOM pode ser feita de duas formas principais: imperativa (JavaScript puro) e declarativa (React). No JavaScript puro, cada operação é explícita: você seleciona um elemento, cria um novo nó e o insere manualmente. No React, você descreve como a interface deve ser em cada estado — o framework resolve as diferenças e aplica as mudanças mínimas necessárias.
Boas práticas de performance: Evite manipulações frequentes que causem reflow (recalculo de layout) e repaint (redesenho). Prefira operações em lote, use DocumentFragment para inserções múltiplas e evite leituras/escritas alternadas de propriedades geométricas.
2. Criando Novos Elementos
O método mais fundamental para criar elementos é document.createElement(), que gera um novo nó HTML sem inseri-lo na página.
// Criando um elemento <div> e um texto
const div = document.createElement('div');
const texto = document.createTextNode('Olá, DOM!');
div.appendChild(texto);
// Inserindo no body
document.body.appendChild(div);
Para inserir elementos em posições específicas, temos várias opções:
const lista = document.getElementById('lista');
const item = document.createElement('li');
item.textContent = 'Item novo';
// No final
lista.appendChild(item);
// No início
lista.prepend(item.cloneNode(true));
// Antes de um elemento específico
const referencia = lista.children[2];
lista.insertBefore(item.cloneNode(true), referencia);
O método append() é mais flexível que appendChild(), aceitando múltiplos nós e strings:
const container = document.getElementById('container');
container.append('Texto direto', document.createElement('hr'), 'Outro texto');
Para inserção rápida de HTML, insertAdjacentHTML() é eficiente e seguro (não reanalisa o elemento pai):
const alvo = document.getElementById('alvo');
alvo.insertAdjacentHTML('beforebegin', '<p>Antes do alvo</p>');
alvo.insertAdjacentHTML('afterend', '<p>Depois do alvo</p>');
3. Modificando Atributos e Conteúdo
Conteúdo textual
Três propriedades principais controlam o conteúdo de um elemento:
const elemento = document.getElementById('exemplo');
// textContent: retorna todo o texto, ignorando tags HTML
elemento.textContent = '<strong>negrito</strong>'; // Exibe literalmente a string
// innerText: considera estilos CSS (mais lento)
elemento.innerText = 'Texto visível';
// innerHTML: interpreta HTML (cuidado com XSS se vier de fonte externa)
elemento.innerHTML = '<strong>Negrito real</strong>';
Atributos
const link = document.querySelector('a');
link.setAttribute('href', 'https://exemplo.com');
link.setAttribute('target', '_blank');
console.log(link.getAttribute('href')); // "https://exemplo.com"
link.removeAttribute('target');
Classes CSS
A API classList é a forma mais limpa e performática de manipular classes:
const card = document.querySelector('.card');
card.classList.add('destaque', 'ativo');
card.classList.remove('inativo');
card.classList.toggle('expandido'); // Adiciona se não existe, remove se existe
console.log(card.classList.contains('destaque')); // true
4. Modificando Estilos e Estrutura
Estilização inline
const box = document.getElementById('box');
box.style.backgroundColor = '#3498db';
box.style.width = '200px';
box.style.cssText = 'background-color: #e74c3c; border-radius: 8px;';
Alterando estrutura
const parent = document.getElementById('parent');
const novoFilho = document.createElement('p');
novoFilho.textContent = 'Substituto';
// Substituir um filho
const antigo = parent.children[0];
parent.replaceChild(novoFilho, antigo);
// Clonar elemento
const cloneSuperficial = antigo.cloneNode(false); // Apenas o nó
const cloneProfundo = antigo.cloneNode(true); // Nó e descendentes
// Normalizar: mescla nós de texto adjacentes
const container = document.getElementById('container');
container.normalize();
Manipulação de formulários
const input = document.querySelector('input[name="email"]');
input.value = 'usuario@exemplo.com';
const checkbox = document.querySelector('#aceito');
checkbox.checked = true;
const select = document.querySelector('#cidade');
select.value = 'sp'; // Deve corresponder ao value de uma option
5. Removendo Elementos do DOM
removeChild() vs remove()
const pai = document.getElementById('lista');
const filho = pai.children[0];
// Método tradicional (precisa do pai)
pai.removeChild(filho);
// Método moderno (diretamente no elemento)
filho.remove(); // Compatível com navegadores modernos
Limpando conteúdo interno
const container = document.getElementById('container');
// Rápido, mas perde referências a event listeners
container.innerHTML = '';
// Mais seguro: preserva event listeners nos elementos removidos
container.textContent = '';
// Loop de remoção (útil para remover com animação ou cleanup)
while (container.firstChild) {
container.removeChild(container.firstChild);
}
Esvaziando um container: loop vs substituição
// Abordagem 1: Substituir o nó inteiro (mais performática)
const pai = document.getElementById('pai');
const novoPai = pai.cloneNode(false); // Apenas o nó vazio
pai.parentNode.replaceChild(novoPai, pai);
// Abordagem 2: Loop (preserva referências ao elemento pai)
while (pai.firstChild) {
pai.removeChild(pai.firstChild);
}
6. Manipulação Eficiente com Fragmentos e Clonagem
DocumentFragment
DocumentFragment é um contêiner leve que não faz parte do DOM ativo. Inseri-lo no DOM não dispara reflow até o momento da inserção:
const fragment = document.createDocumentFragment();
const lista = document.getElementById('lista-grande');
for (let i = 0; i < 1000; i++) {
const li = document.createElement('li');
li.textContent = `Item ${i + 1}`;
fragment.appendChild(li);
}
// Única inserção → único reflow
lista.appendChild(fragment);
Clonagem profunda vs superficial
const original = document.getElementById('template');
// Superficial: apenas o nó, sem filhos
const cloneVazio = original.cloneNode(false);
// Profunda: nó e toda a subárvore
const cloneCompleto = original.cloneNode(true);
// Útil para reutilizar estruturas complexas
document.body.appendChild(cloneCompleto);
Evitando reflows
// Ruim: causa reflow a cada iteração
for (let i = 0; i < 100; i++) {
document.getElementById('container').innerHTML += `<p>${i}</p>`;
}
// Bom: constrói tudo em lote
const fragment = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const p = document.createElement('p');
p.textContent = i;
fragment.appendChild(p);
}
document.getElementById('container').appendChild(fragment);
Para animações, use requestAnimationFrame para sincronizar com o ciclo de renderização do navegador.
7. Perspectiva React: Abordagem Declarativa
No React, você não manipula o DOM diretamente. O Virtual DOM calcula a diferença entre o estado anterior e o novo, aplicando apenas as mudanças necessárias.
Criando elementos
// React.createElement (sem JSX)
const elemento = React.createElement('h1', { className: 'titulo' }, 'Olá React');
// JSX (recomendado)
const elementoJSX = <h1 className="titulo">Olá React</h1>;
Atualização via estado
function Lista() {
const [itens, setItens] = React.useState(['Item 1', 'Item 2']);
const adicionarItem = () => {
setItens([...itens, `Item ${itens.length + 1}`]);
};
const removerItem = (index) => {
setItens(itens.filter((_, i) => i !== index));
};
return (
<div>
<button onClick={adicionarItem}>Adicionar</button>
<ul>
{itens.map((item, index) => (
<li key={index}>
{item}
<button onClick={() => removerItem(index)}>Remover</button>
</li>
))}
</ul>
</div>
);
}
A propriedade key é essencial para que o React identifique cada elemento de forma única, otimizando a reconciliação do Virtual DOM.
Remoção via estado
No React, "remover" significa simplesmente não incluir o elemento no retorno do componente:
function App() {
const [mostrar, setMostrar] = React.useState(true);
return (
<div>
<button onClick={() => setMostrar(!mostrar)}>
{mostrar ? 'Esconder' : 'Mostrar'} saudação
</button>
{mostrar && <p>Olá, mundo!</p>}
</div>
);
}
O React remove automaticamente o <p> do DOM real quando mostrar se torna false.
Referências
- MDN Web Docs: Manipulando o DOM — Guia completo sobre a API do DOM, incluindo criação, modificação e remoção de elementos.
- MDN Web Docs: DocumentFragment — Documentação oficial sobre o uso de fragmentos para inserções eficientes.
- React Documentation: Rendering Elements — Documentação oficial sobre como React cria e atualiza elementos no Virtual DOM.
- JavaScript.info: Modifying the document — Tutorial detalhado em inglês sobre criação, inserção e remoção de nós no DOM.
- W3Schools: DOM HTML — Referência prática com exemplos interativos sobre manipulação de elementos HTML via JavaScript.
- React.dev: Conditional Rendering — Guia oficial sobre renderização condicional e remoção de componentes em React.