Mesmo na era de frameworks reativos como React, Vue e Angular, compreender a manipulação nativa do DOM é uma habilidade fundamental para qualquer desenvolvedor frontend. É essa base que permite entender o que acontece "sob o capô" das bibliotecas modernas, além de ser a solução ideal para projetos leves em Vanilla JavaScript. As APIs modernas do navegador são elegantes e poderosas, tornando o antigo jQuery praticamente desnecessário.
Selecionando Elementos no DOM
Esqueça os seletores complexos. Com o padrão moderno, você consegue buscar qualquer elemento utilizando a mesma sintaxe de seletores do CSS.
// Selecionar um único elemento
const header = document.querySelector('.header');
const submitBtn = document.getElementById('submit-btn');
const firstArticle = document.querySelector('article:first-of-type');
// Selecionar múltiplos elementos (retorna uma NodeList)
const cards = document.querySelectorAll('.card');
const links = document.querySelectorAll('nav a');
// Iterar sobre uma NodeList diretamente
cards.forEach(card => {
card.classList.add('loaded');
});
// Converter para Array para usar métodos como filter ou map
const cardArray = [...document.querySelectorAll('.card')];
const visibleCards = cardArray.filter(c => !c.hidden);
Modificando Elementos e Atributos
Alterar o conteúdo, estilos e comportamentos de um elemento é simples e direto com as propriedades nativas.
const el = document.querySelector('.hero-title');
// Alterar texto (seguro contra injeção de HTML)
el.textContent = 'Olá, Mundo!';
// Alterar HTML (⚠️ Use com cuidado para evitar ataques XSS)
el.innerHTML = '<strong>Bem-vindo</strong> ao site!';
// Manipulação de Atributos
el.setAttribute('role', 'heading');
el.getAttribute('data-id');
el.removeAttribute('hidden');
// Uso de Dataset (atributos data-*)
el.dataset.userId = '123'; // Define data-user-id="123"
console.log(el.dataset.userId); // Retorna "123"
// Gerenciamento de Classes CSS
el.classList.add('active', 'visible');
el.classList.remove('loading');
el.classList.toggle('dark-mode');
el.classList.contains('active'); // true/false
el.classList.replace('old-class', 'new-class');
// Estilos Inline
el.style.color = '#6366f1';
el.style.setProperty('--accent', '#22d3ee');
Criação e Inserção Dinâmica
Adicionar novos elementos à página em tempo de execução é essencial para interfaces dinâmicas.
// Criar um novo elemento
const card = document.createElement('div');
card.className = 'card';
card.innerHTML = `
<h3>${title}</h3>
<p>${description}</p>
`;
// Inserir no DOM
container.appendChild(card); // Ao final do container
container.prepend(card); // No início do container
container.insertBefore(card, referenceElement); // Antes de um elemento específico
// Métodos modernos de inserção
element.before(newElement); // Antes do elemento
element.after(newElement); // Depois do elemento
element.replaceWith(newElement); // Substitui o elemento atual
// Remover do DOM
element.remove();
// Clonar um elemento
const clone = template.cloneNode(true); // true realiza uma cópia profunda
Gerenciamento de Eventos
Interatividade é o coração da web. O método addEventListener é a forma padrão de ouvir interações do usuário.
const button = document.querySelector('#submit');
// Adicionar um ouvinte de evento
button.addEventListener('click', (event) => {
event.preventDefault(); // Evita o comportamento padrão
console.log('Botão clicado!', event.target);
});
// Remover evento (requer uma função nomeada)
function handleClick(e) { /* lógica */ }
button.addEventListener('click', handleClick);
button.removeEventListener('click', handleClick);
// Eventos mais utilizados
element.addEventListener('input', handler); // Mudanças em tempo real em inputs
element.addEventListener('change', handler); // Quando o input perde o foco
element.addEventListener('submit', handler); // Envio de formulários
element.addEventListener('keydown', handler); // Tecla pressionada
element.addEventListener('scroll', handler); // Rolagem da página
window.addEventListener('load', handler); // Quando tudo foi carregado
Delegação de Eventos
Em vez de adicionar ouvintes a centenas de elementos filhos, adicione um único ouvinte ao pai e use event.target. Isso economiza memória e funciona com elementos adicionados dinamicamente via JavaScript.
// ❌ Abordagem Ineficiente — um listener para cada item
document.querySelectorAll('.card').forEach(card => {
card.addEventListener('click', handleCardClick);
});
// ✅ Abordagem Otimizada — um único listener no container pai
document.querySelector('.card-grid').addEventListener('click', (e) => {
const card = e.target.closest('.card');
if (!card) return; // Se o clique não foi em um card, ignora
const id = card.dataset.id;
handleCardClick(id);
});
Uso da Tag Template
A tag HTML <template> permite armazenar fragmentos de marcação que não são renderizados até que você os ative via script.
<!-- Template HTML (invisível na renderização inicial) -->
<template id="card-template">
<div class="card">
<h3 class="card-title"></h3>
<p class="card-desc"></p>
</div>
</template>
<script>
const template = document.getElementById('card-template');
function addCard(title, desc) {
const clone = template.content.cloneNode(true);
clone.querySelector('.card-title').textContent = title;
clone.querySelector('.card-desc').textContent = desc;
document.querySelector('.grid').appendChild(clone);
}
</script>
Dicas de Performance no DOM
- Agrupe atualizações do DOM — Utilize
DocumentFragmentpara realizar múltiplas inserções de uma só vez, evitando reflows excessivos. - Prefira delegação de eventos em listas longas para reduzir o consumo de memória.
- Evite o "Layout Thrashing" — Não alterne entre ler propriedades de layout (como
offsetHeight) e escrever estilos (comostyle.height) dentro de loops. - Use
requestAnimationFramepara animações ou atualizações visuais complexas. - Aplique Debounce ou Throttle em eventos que disparam muito rápido, como
scrolleresize.
Otimize seu Código com Nossas Ferramentas
Acelere seu desenvolvimento com nossos minificadores e formatadores gratuitos.