No artigo anterior aprendemos a selecionar e modificar elementos do DOM. Mas um site estático que muda apenas quando o JavaScript carrega não é muito útil. O verdadeiro poder aparece quando o código reage ao usuário — quando ele clica, digita, envia um formulário, passa o mouse sobre um elemento, pressiona uma tecla.
Esse mecanismo de reação se chama evento. E entender eventos é entender como páginas web realmente funcionam.
O que é um evento?
Um evento é qualquer coisa que acontece no navegador — uma ação do usuário ou do próprio sistema. O navegador fica constantemente monitorando a página e, quando algo acontece, dispara um evento. Você pode "ouvir" esses eventos e executar código em resposta.
Exemplos de eventos:
- Usuário clicou em um botão
- Usuário digitou no campo de busca
- Formulário foi enviado
- Página terminou de carregar
- Mouse passou por cima de um elemento
- Tecla foi pressionada
- Janela foi redimensionada
addEventListener — a forma correta
A maneira moderna e recomendada de registrar um evento:
const botao = document.querySelector("#meuBotao");
botao.addEventListener("click", function() {
console.log("Botão clicado!");
});
// Com arrow function (mais comum no código moderno)
botao.addEventListener("click", () => {
console.log("Botão clicado!");
});
A sintaxe é sempre:
elemento.addEventListener("nomeDoEvento", funcaoCallback);
A função callback é executada toda vez que o evento ocorre no elemento.
O objeto Event
Quando um evento é disparado, o navegador passa automaticamente um objeto com informações sobre esse evento para o callback:
const botao = document.querySelector("#meuBotao");
botao.addEventListener("click", (evento) => {
console.log(evento.type); // "click"
console.log(evento.target); // o elemento que foi clicado
console.log(evento.target.id); // "meuBotao"
console.log(evento.timeStamp); // momento em que ocorreu
console.log(evento.clientX); // posição X do mouse
console.log(evento.clientY); // posição Y do mouse
});
Por convenção, esse parâmetro é chamado de event, evt ou simplesmente e.
Eventos de mouse
const caixa = document.querySelector(".caixa");
// Clique simples
caixa.addEventListener("click", () => {
console.log("Clicou!");
});
// Duplo clique
caixa.addEventListener("dblclick", () => {
console.log("Duplo clique!");
});
// Mouse entrou no elemento
caixa.addEventListener("mouseenter", () => {
caixa.classList.add("hover");
});
// Mouse saiu do elemento
caixa.addEventListener("mouseleave", () => {
caixa.classList.remove("hover");
});
// Mouse se moveu sobre o elemento
caixa.addEventListener("mousemove", (e) => {
console.log(`Posição: X=${e.clientX}, Y=${e.clientY}`);
});
// Botão do mouse pressionado
caixa.addEventListener("mousedown", () => {
caixa.classList.add("pressionado");
});
// Botão do mouse solto
caixa.addEventListener("mouseup", () => {
caixa.classList.remove("pressionado");
});
Eventos de teclado
const input = document.querySelector("#busca");
// Tecla pressionada (dispara continuamente se mantiver pressionada)
input.addEventListener("keydown", (e) => {
console.log(`Tecla pressionada: ${e.key}`);
console.log(`Código: ${e.code}`);
// Detectar teclas especiais
if (e.key === "Enter") {
console.log("Enter pressionado — executar busca!");
}
if (e.key === "Escape") {
input.value = "";
console.log("Campo limpo.");
}
});
// Tecla solta
input.addEventListener("keyup", (e) => {
console.log(`Digitado até agora: ${input.value}`);
});
// Combinações de teclas
document.addEventListener("keydown", (e) => {
if (e.ctrlKey && e.key === "s") {
e.preventDefault(); // cancela o comportamento padrão (salvar página)
console.log("Salvando dados...");
}
});
Eventos de formulário
Os eventos de formulário são fundamentais para qualquer aplicação web:
const formulario = document.querySelector("#meuForm");
const campoNome = document.querySelector("#nome");
const campoEmail = document.querySelector("#email");
// Evento input — dispara a cada caractere digitado
campoNome.addEventListener("input", (e) => {
console.log(`Nome sendo digitado: ${e.target.value}`);
});
// Evento change — dispara quando o campo perde foco E o valor mudou
campoEmail.addEventListener("change", (e) => {
console.log(`E-mail confirmado: ${e.target.value}`);
});
// Evento focus — campo recebeu foco
campoNome.addEventListener("focus", () => {
campoNome.classList.add("ativo");
});
// Evento blur — campo perdeu foco
campoNome.addEventListener("blur", () => {
campoNome.classList.remove("ativo");
// Bom momento para validar o campo
if (campoNome.value.trim().length < 2) {
console.log("Nome muito curto.");
}
});
// Evento submit — formulário enviado
formulario.addEventListener("submit", (e) => {
e.preventDefault(); // SEMPRE previna o comportamento padrão (recarregar a página)
const dados = {
nome: campoNome.value.trim(),
email: campoEmail.value.trim(),
};
console.log("Formulário enviado:", dados);
});
O e.preventDefault() no submit é essencial — sem ele a página recarrega e você perde todos os dados.
Eventos da janela e documento
// Página completamente carregada (DOM + imagens + recursos)
window.addEventListener("load", () => {
console.log("Página totalmente carregada.");
});
// DOM pronto (sem esperar imagens)
document.addEventListener("DOMContentLoaded", () => {
console.log("DOM pronto. Pode manipular elementos.");
});
// Janela redimensionada
window.addEventListener("resize", () => {
console.log(`Nova largura: ${window.innerWidth}px`);
});
// Usuário rolou a página
window.addEventListener("scroll", () => {
const posicao = window.scrollY;
if (posicao > 300) {
document.querySelector("#voltarTopo").classList.remove("oculto");
}
});
// Antes de sair da página
window.addEventListener("beforeunload", (e) => {
e.preventDefault();
// Alguns navegadores exibem um diálogo de confirmação
});
Delegação de eventos — Event Delegation
Um padrão fundamental e muito eficiente: em vez de adicionar um listener para cada elemento filho, você adiciona um único listener no elemento pai e usa event.target para identificar quem foi clicado.
// ❌ Ineficiente — um listener para cada item
const itens = document.querySelectorAll(".item");
itens.forEach(item => {
item.addEventListener("click", () => {
item.classList.toggle("selecionado");
});
});
// ✅ Eficiente — um listener no pai
const lista = document.querySelector("#lista");
lista.addEventListener("click", (e) => {
// Verifica se o clique foi em um <li>
if (e.target.tagName === "LI") {
e.target.classList.toggle("selecionado");
}
});
A delegação de eventos é especialmente importante quando os elementos são criados dinamicamente — listeners adicionados antes da criação do elemento não funcionam, mas um listener no pai captura eventos de qualquer filho, inclusive os criados depois.
Removendo eventos
// Para remover um evento, a função deve ter nome (não pode ser anônima)
function aoClicar() {
console.log("Clicado!");
}
const botao = document.querySelector("#botao");
// Adiciona
botao.addEventListener("click", aoClicar);
// Remove — usa exatamente a mesma referência de função
botao.removeEventListener("click", aoClicar);
Exemplo completo — barra de busca ao vivo
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>Busca ao Vivo</title>
<style>
body { font-family: sans-serif; max-width: 500px; margin: 2rem auto; padding: 1rem; }
input { width: 100%; padding: .75rem; font-size: 1rem; border: 2px solid #ddd; border-radius: 8px; }
input:focus { outline: none; border-color: royalblue; }
ul { list-style: none; padding: 0; margin-top: 1rem; }
li { padding: .5rem .75rem; border-bottom: 1px solid #eee; cursor: pointer; }
li:hover { background: #f0f4ff; }
.oculto { display: none; }
.destaque { background: yellow; }
#contador { color: gray; font-size: .9rem; margin-top: .5rem; }
</style>
</head>
<body>
<h2>🔍 Busca de Linguagens</h2>
<input type="text" id="busca" placeholder="Digite para filtrar...">
<p id="contador"></p>
<ul id="lista"></ul>
<script>
const linguagens = [
"JavaScript", "Python", "Java", "TypeScript",
"Go", "Rust", "PHP", "Ruby", "Swift", "Kotlin",
"C#", "C++", "Dart", "Scala", "Elixir"
];
const input = document.querySelector("#busca");
const lista = document.querySelector("#lista");
const contador = document.querySelector("#contador");
// Renderiza a lista com base em um filtro
function renderizarLista(filtro = "") {
const termo = filtro.toLowerCase().trim();
const filtradas = linguagens.filter(lang =>
lang.toLowerCase().includes(termo)
);
// Limpa a lista atual
lista.innerHTML = "";
// Cria novos itens
filtradas.forEach(lang => {
const li = document.createElement("li");
// Destaca o termo buscado dentro do texto
if (termo) {
const regex = new RegExp(`(${termo})`, "gi");
li.innerHTML = lang.replace(regex, '<mark>$1</mark>');
} else {
li.textContent = lang;
}
lista.appendChild(li);
});
// Atualiza o contador
contador.textContent = filtradas.length === 0
? "Nenhum resultado encontrado."
: `${filtradas.length} linguagem(ns) encontrada(s).`;
}
// Renderiza tudo ao carregar
renderizarLista();
// Filtra a cada caractere digitado
input.addEventListener("input", (e) => {
renderizarLista(e.target.value);
});
// Limpa com Escape
input.addEventListener("keydown", (e) => {
if (e.key === "Escape") {
input.value = "";
renderizarLista();
input.focus();
}
});
// Delegação de evento na lista
lista.addEventListener("click", (e) => {
if (e.target.tagName === "LI" || e.target.tagName === "MARK") {
const lang = e.target.closest("li").textContent;
input.value = lang;
renderizarLista(lang);
}
});
</script>
</body>
</html>
Salve e abra no navegador. Você verá uma busca ao vivo funcionando com destaque de texto, contador e seleção por clique — tudo com eventos JavaScript puro.
Boas práticas com eventos
// ✅ 1. Sempre use addEventListener — nunca atributos HTML inline
// ❌ Ruim
// <button onclick="fazerAlgo()">Clique</button>
// ✅ Bom
botao.addEventListener("click", fazerAlgo);
// ✅ 2. Sempre chame preventDefault() no submit de formulários
formulario.addEventListener("submit", (e) => {
e.preventDefault();
// processar dados
});
// ✅ 3. Use delegação para listas e elementos dinâmicos
pai.addEventListener("click", (e) => {
if (e.target.matches(".item")) {
// agir sobre o item correto
}
});
// ✅ 4. Nomeie suas funções de callback para poder removê-las depois
function tratarClique() { /* ... */ }
botao.addEventListener("click", tratarClique);
botao.removeEventListener("click", tratarClique);
// ✅ 5. Cuidado com scroll e resize — use debounce para evitar
// excesso de chamadas (veremos isso em artigos futuros)
Tarefa para você
Crie uma página com um campo de texto e implemente:
- Exibir em tempo real quantos caracteres foram digitados
- Mudar a cor da borda para vermelho se passar de 50 caracteres
- Ao pressionar
Enter, exibir o texto em um parágrafo abaixo - Ao pressionar
Escape, limpar o campo - Exibir uma mensagem de boas-vindas quando o campo receber foco pela primeira vez (apenas uma vez — remova o listener depois)
Conclusão
Neste artigo você aprendeu:
- O que são eventos e como o navegador os dispara
addEventListenere o objetoevent- Eventos de mouse, teclado, formulário e janela
- Como usar
e.preventDefault()corretamente - O padrão de delegação de eventos
- Como remover listeners com
removeEventListener - Um exemplo completo de busca ao vivo
No próximo artigo vamos aprender a criar e remover elementos dinamicamente — construindo partes da página com JavaScript puro, sem precisar modificar o HTML.
📌 Próximo artigo: Aula 13 — Criando e Removendo Elementos Dinamicamente
📚 Fontes e Referências
- MDN Web Docs — Introduction to Events: https://developer.mozilla.org/pt-BR/docs/Learn/JavaScript/Building_blocks/Events
- MDN Web Docs — EventTarget.addEventListener: https://developer.mozilla.org/pt-BR/docs/Web/API/EventTarget/addEventListener
- MDN Web Docs — Event Reference: https://developer.mozilla.org/pt-BR/docs/Web/Events
- MDN Web Docs — Event Delegation: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_delegation
- JavaScript.info — Introduction to browser events: https://javascript.info/introduction-browser-events
- JavaScript.info — Event Delegation: https://javascript.info/event-delegation
- Eloquent JavaScript, Cap. 15 — Handling Events: https://eloquentjavascript.net/15_event.html
- JavaScript & JQuery — Jon Duckett (Alta Books)