Eventos são ações ou ocorrências que acontecem no navegador, como cliques, teclas pressionadas ou carregamento de página. Manipular eventos é essencial para criar interfaces interativas e dinâmicas. Nesta aula, você aprenderá a registrar, gerenciar e remover ouvintes de eventos (listeners) no DOM, além de explorar o objeto event que carrega informações detalhadas sobre cada ocorrência.

Dominar eventos no DOM permite controlar a interação do usuário com a página, desde validação de formulários até animações complexas. Vamos aos conceitos fundamentais.

addEventListener

O método addEventListener é a forma moderna e recomendada de associar uma função a um evento em um elemento do DOM. Ele aceita três parâmetros: o tipo do evento (string), a função de callback (handler) e um objeto opcional de opções (como once, capture ou passive).

Diferente de atributos inline (como onclick), addEventListener permite adicionar múltiplos listeners para o mesmo evento no mesmo elemento, sem sobrescrever outros. Além disso, oferece mais controle sobre a propagação e a captura de eventos.

// Seleciona o elemento
const botao = document.getElementById('meuBotao');

// Define a função de callback
function handleClick() {
  console.log('Botão clicado!');
}

// Adiciona o listener
botao.addEventListener('click', handleClick);

// Exemplo com função anônima
botao.addEventListener('click', function() {
  alert('Outro handler');
});

// Usando arrow function
botao.addEventListener('click', () => console.log('Arrow function'));

O terceiro parâmetro pode ser um objeto com opções como once (executa apenas uma vez), capture (ativa a fase de captura) e passive (indica que o listener não chamará preventDefault(), melhorando performance em scroll, por exemplo).

// Executa apenas uma vez
botao.addEventListener('click', function() {
  console.log('Executado apenas uma vez');
}, { once: true });

// Na fase de captura (padrão é false - bubbling)
document.addEventListener('click', function() {
  console.log('Captura');
}, true);

Objeto event

Quando um evento é disparado, o navegador cria um objeto event que contém propriedades e métodos relacionados à ocorrência. Esse objeto é passado automaticamente como argumento para a função de callback. Você pode nomeá-lo como preferir (comum usar e, evt ou event).

Propriedades importantes incluem target (elemento que disparou o evento), currentTarget (elemento ao qual o listener está associado), type (tipo do evento), preventDefault() (cancela ação padrão), stopPropagation() (interrompe propagação) e stopImmediatePropagation() (interrompe propagação e outros listeners do mesmo elemento).

document.querySelector('a').addEventListener('click', function(event) {
  event.preventDefault(); // evita navegar para o link
  console.log('Link clicado, mas sem navegação');
  console.log('Target:', event.target);
  console.log('Type:', event.type);
});

// Exemplo de propagação
document.getElementById('pai').addEventListener('click', function(e) {
  console.log('Clicou no pai');
});
document.getElementById('filho').addEventListener('click', function(e) {
  e.stopPropagation(); // não propaga para o pai
  console.log('Clicou no filho');
});

Para eventos de teclado, o objeto event possui key, code, ctrlKey, entre outros. Para mouse, clientX, clientY, button, etc.

Tipos comuns

Existem dezenas de tipos de eventos no DOM. Os mais utilizados incluem:

  • mouse: click, dblclick, mouseenter, mouseleave, mousemove, mousedown, mouseup
  • teclado: keydown, keyup, keypress (depreciado)
  • formulário: submit, change, input, focus, blur
  • documento/janela: DOMContentLoaded, load, resize, scroll, unload
  • toque (mobile): touchstart, touchend, touchmove

Exemplo prático com evento de teclado:

document.addEventListener('keydown', function(event) {
  console.log('Tecla pressionada:', event.key);
  if (event.key === 'Enter') {
    alert('Enter pressionado!');
  }
});

Exemplo com evento de formulário:

const form = document.getElementById('meuForm');
form.addEventListener('submit', function(e) {
  e.preventDefault(); // evita recarregar a página
  const dados = new FormData(form);
  console.log('Dados do formulário:', Object.fromEntries(dados));
});

Removendo listeners

Para remover um listener, use o método removeEventListener com os mesmos parâmetros usados na adição (tipo, função e opções). É crucial que a função de callback seja a mesma referência; não é possível remover listeners anônimos a menos que você mantenha a referência em uma variável.

function handleClick() {
  console.log('Removendo este listener');
}

botao.addEventListener('click', handleClick);

// Mais tarde, remove
botao.removeEventListener('click', handleClick);

// Tentativa de remover função anônima (não funciona)
botao.addEventListener('click', function() {
  console.log('Nunca será removido');
});
// botao.removeEventListener('click', function() {...}); // não remove!

Para listeners com opções, passe o mesmo objeto de opções (a referência deve ser a mesma).

const options = { once: true };
botao.addEventListener('click', handleClick, options);
botao.removeEventListener('click', handleClick, options);

Uma boa prática é sempre remover listeners quando eles não forem mais necessários, especialmente em componentes que são destruídos, para evitar vazamento de memória.

Boas práticas e observações finais

Prefira addEventListener em vez de atributos HTML como onclick. Isso mantém a separação entre comportamento e estrutura. Use delegação de eventos sempre que possível: em vez de adicionar listeners a vários elementos filhos, adicione um único listener ao pai e verifique event.target. Isso melhora performance e simplifica o código.

Evite funções anônimas se precisar remover o listener depois. Lembre-se de que a propagação de eventos ocorre em três fases: captura (do document até o target), alvo (target) e bolha (do target de volta ao document). O terceiro parâmetro de addEventListener controla em qual fase o listener é executado (padrão é fase de bolha).

Referências

Exercícios

  1. Crie um botão que, ao ser clicado, exiba um alerta com a mensagem "Olá, mundo!". Use addEventListener.

    ✓ Resposta:
    const btn = document.getElementById('meuBotao');
    btn.addEventListener('click', function() {
      alert('Olá, mundo!');
    });
    
  2. Adicione um evento de teclado que, ao pressionar a tecla 'Escape', exiba no console "Tecla Escape pressionada".

    ✓ Resposta:
    document.addEventListener('keydown', function(event) {
      if (event.key === 'Escape') {
        console.log('Tecla Escape pressionada');
      }
    });
    
  3. Utilize o objeto event para evitar que um link (<a>) navegue para outra página. Em vez disso, exiba o href no console.

    ✓ Resposta:
    const link = document.querySelector('a');
    link.addEventListener('click', function(event) {
      event.preventDefault();
      console.log('Link clicado, href:', event.target.href);
    });
    
  4. Crie um listener que execute apenas uma vez (use a opção once). Após o clique, o listener não deve mais responder.

    ✓ Resposta:
    const btn = document.getElementById('meuBotao');
    btn.addEventListener('click', function() {
      console.log('Este listener será executado apenas uma vez');
    }, { once: true });
    
  5. Adicione um listener a um botão e, em seguida, remova-o usando removeEventListener. Verifique se o listener foi removido (o botão não deve mais responder).

    ✓ Resposta:
    function handleClick() {
      console.log('Botão clicado');
    }
    
    const btn = document.getElementById('meuBotao');
    btn.addEventListener('click', handleClick);
    
    // Remove após 3 segundos
    setTimeout(() => {
      btn.removeEventListener('click', handleClick);
      console.log('Listener removido');
    }, 3000);