Javascript

Eventos: click, input, submit e muito mais Já leu

9 min de leitura

Eventos: click, input, submit e muito mais
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 &eac

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:

  1. Exibir em tempo real quantos caracteres foram digitados
  2. Mudar a cor da borda para vermelho se passar de 50 caracteres
  3. Ao pressionar Enter, exibir o texto em um parágrafo abaixo
  4. Ao pressionar Escape, limpar o campo
  5. 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
  • addEventListener e o objeto event
  • 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

Comentários

Mais em Javascript

LocalStorage e SessionStorage
LocalStorage e SessionStorage

Imagine que o usu&aacute;rio passou dez minutos preenchendo uma lista de tare...

Escopo, Hoisting e Closures
Escopo, Hoisting e Closures

Este &eacute; um dos artigos mais importantes da s&eacute;rie. N&atilde;o por...

O que é o DOM e como o JavaScript interage com o HTML
O que é o DOM e como o JavaScript interage com o HTML

At&eacute; agora todo o nosso c&oacute;digo rodou no console &mdash; um ambie...