Event listeners em JavaScript: click, submit, scroll e delegação
Event listeners em JavaScript
Event listeners em JavaScript: click, submit, scroll | We.Inc
Veja eventos disparando em um log ao vivo e copie padrões de addEventListener para click, submit, scroll, delegação, once, passive e limpeza com AbortController.
Um event listener é uma função que o navegador chama quando algo acontece com um elemento, como um clique, o envio de um formulário ou uma rolagem. Você adiciona um com element.addEventListener(type, handler, options). O objeto de opções ativa once, passive, capture ou um sinal de abort, e removeEventListener desconecta a mesma função depois.
Opções do addEventListener
Opção
Padrão
Efeito
Remove o listener automaticamente depois da primeira chamada
false (true para wheel e touch em window, document e body)
Promete não chamar preventDefault, então a rolagem nunca espera
Executa na descida até o alvo, em vez de na volta para cima
Um AbortSignal; abortá-lo remove o listener
Eventos ficam mais fáceis de entender quando você consegue vê-los. O log de eventos abaixo registra cada chamada de listener em uma pequena área de teste, então você pode clicar, digitar, enviar e rolar e acompanhar a ordem, o alvo e o efeito de cada opção. Depois, copie os padrões para as tarefas que você realmente tem.
Use os controles da área de teste: clique nos botões, digite no campo, envie o formulário e role a caixa.
Cada chamada de listener aparece no log com o tipo do evento, o elemento que o iniciou e o elemento que o tratou.
Ative once para ver um listener sumir depois de uma chamada, ou desative a delegação para ver a lista tratar os cliques item por item.
Copie qualquer um dos exemplos abaixo. Todos são JavaScript puro, sem biblioteca.
Passe uma função nomeada quando pretender remover o listener. Uma arrow function inline não pode ser encontrada depois.
O AbortController remove um grupo inteiro de listeners com uma única chamada a abort(), o que combina com componentes que são montados e desmontados.
Escute submit no formulário, não click no botão, para que apertar Enter em um campo também seja tratado.
Use event.target.closest("selector") em handlers delegados. Um clique em um ícone dentro de um botão ainda encontra o botão.
focus e blur não fazem bubbling. Delegue focusin e focusout no lugar deles.
Perguntas frequentes
O que é delegação de eventos?
Em vez de adicionar um listener em cada item, você adiciona um só em um elemento pai comum. Como a maioria dos eventos sobe na árvore, o pai recebe os cliques de todos os filhos, inclusive de itens adicionados depois, e usa event.target para saber qual foi clicado.
Por que o removeEventListener não remove o meu listener?
Ele precisa receber a mesma referência de função e a mesma configuração de capture passadas ao addEventListener. Duas arrow functions com código idêntico continuam sendo funções diferentes, então defina o handler uma vez e passe essa variável nas duas chamadas.
O que passive: true faz?
Diz ao navegador que o seu handler não vai chamar preventDefault, então a página pode começar a rolar na hora, sem esperar o seu código terminar. Os navegadores já usam passive como padrão para listeners de wheel e touch em window, document e body.
Qual é a diferença entre target e currentTarget?
target é o elemento mais interno onde o evento começou, e ele não muda enquanto o evento sobe. currentTarget é o elemento cujo listener está executando agora, que muda a cada nível.
form.submit() dispara o evento submit?
Não. Chamar form.submit() por script pula o evento submit e pula a validação. Chame form.requestSubmit() quando quiser que os seus listeners de submit e as verificações nativas sejam executados.
addEventListener ou onclick?
A propriedade onclick guarda uma única função, então atribuir uma segunda substitui a primeira. O addEventListener permite que vários listeners independentes compartilhem um elemento e aceita o objeto de opções, por isso é o melhor padrão.
Como um evento se propaga
Um evento disparado passa por três fases. Ele desce do window até o alvo na fase de captura, chega ao alvo e depois sobe de volta por cada ancestral (bubbling). Os listeners executam na fase de bubbling, a não ser que você peça capture.
stopPropagation interrompe o caminho, então os ancestrais nunca recebem o evento. Use raramente, porque listeners delegados e ferramentas de analytics mais acima na árvore param de funcionar sem aviso.
Role sem deixar a página lenta
Eventos de scroll podem disparar muitas vezes a cada quadro de movimento. Mantenha o handler mínimo, leia posições em vez de alterar o layout e agrupe as atualizações visuais dentro de requestAnimationFrame.
Para tarefas como revelar elementos quando entram na tela, um IntersectionObserver geralmente sai mais barato que medir a cada rolagem. O evento scrollend, Baseline desde dezembro de 2025 segundo a MDN, dispara uma vez quando o movimento para.
Limpando listeners
Listeners em objetos que vivem muito tempo, como window ou document, mantêm vivo o handler e tudo o que ele referencia. Quando a parte da página que precisava deles some, remova-os.
A opção signal deixa isso organizado. Crie um AbortController por funcionalidade, passe o signal dele para cada listener e chame abort() uma vez na desmontagem.
Os tipos de evento que você mais vai usar
Eventos comuns e onde escutá-los
Evento
Dispara quando
Faz bubbling?
Um ponteiro é pressionado e solto, ou Enter ou Space em um botão
Sim
O valor de um campo muda enquanto o visitante digita
Sim
O valor de um campo é confirmado, por exemplo no blur ou em uma seleção
Sim
Um formulário é enviado; dispara no elemento form
Sim
Uma tecla é pressionada
Sim
focus / blur
Um elemento ganha ou perde o foco
Não
focusin / focusout
Igual a focus e blur, mas com bubbling
Sim
DOMContentLoaded
O HTML foi analisado e os scripts deferred já executaram; escute no document
Não se aplica
Padrões para copiar
Click com um handler nomeado que você pode remover
Guardar a função em uma variável é o que faz o removeEventListener funcionar.
Tratar o envio de um formulário sem recarregar
preventDefault impede a navegação do próprio navegador. event.submitter diz qual botão de envio foi usado.
Delegação de eventos em uma lista
Um listener na lista trata todos os botões de excluir, inclusive de linhas adicionadas depois que a página carregou.
Um listener de scroll passive limitado a uma atualização por quadro
passive: true deixa a rolagem começar na hora, e requestAnimationFrame limita o trabalho a uma vez por quadro.
once e AbortController
O primeiro listener executa uma única vez. Os outros são todos removidos juntos por uma chamada a abort().
Atalho de teclado que ignora digitação em campos
Verificar o alvo impede que o atalho dispare enquanto alguém digita uma barra em uma caixa de busca.
Maçãs
Pão
Café
click no botão: alvo {target}
(once: agora removido)
click chegou à área de teste (fase {phase}): alvo {target}, currentTarget {current}
input: o valor agora é "{value}"
change: valor confirmado
submit no formulário, submitter {submitter}; preventDefault impediu o recarregamento
scroll (passive, um por quadro): scrollTop {n}
click delegado na lista: item {item}
listener por item: {item}
Log de eventos ao vivo
Clique, digite, envie e role na área de teste. Cada chamada de listener é gravada no log com o tipo, o alvo e o alvo atual.