Se você usa jQuery para lidar com a camada de comportamento de seus sites/apps, muito provavelmente já se deparou (e se depara) com situações em que o uso de Delegação de Evento ou Event Delegation é indispensável para não impactar negativamente na performance. De fato, saber como usar eventos com o método .on() de jQuery é uma das primeiras lições ao se aprender a usar a biblioteca e, ali mesmo, é mostrado como realizar a delegação de eventos de maneira bem simples.
Mas você sabe como fazer a delegação de eventos em JavaScript puro? Não é tão simples quanto usar uma biblioteca parruda como jQuery, mas certamente é bastante acessível e possível de se fazer no dia-a-dia. Neste artigo, aprenda mais sobre Delegação de Evento (Event Delegation) em JavaScript puro (Vanilla JavaScript).
Uma das metodologias “quentes” no mundo JavaScript é a delegação de evento. E por boas razões. Delegação de evento permite que você evite adicionar “ouvintes” (listeners) de eventos para nós específicos do DOM; em vez disso, o “ouvinte” (listener) de evento é adicionado a um dos pais deste(s) nó(s). Esse listener de eventos analisa os eventos que “borbulharam para cima” (bubbled) para encontrar uma correspondência em elementos filho — se não souber bem o que é isso, leia um excelente artigo sobre captura de eventos e bubbling em JavaScript (em inglês). O conceito-base é bastante simples, mas muitas pessoas não entendem o quão bem Delegação de Eventos funciona e como isso impacta de maneira positiva na performance de uma aplicação!
Por exemplo, digamos que exista uma lista com vários itens:
1 2 3 4 5 6 7 8 |
<ul id="parent-list"> <li id="post-1">Item 1</li> <li id="post-2">Item 2</li> <li id="post-3">Item 3</li> <li id="post-4">Item 4</li> <li id="post-5">Item 5</li> <li id="post-6">Item 6</li> </ul> |
Consideremos, também, que alguma coisa precisa acontecer quando cada elemento filho é clicado. Você pode adicionar um listener de eventos separado para cada elemento <li>
individualmente, mas e se, por quaisquer outras interações/motivos, elementos <li>
são adicionados e/ou removidos da lista? Adicionar e remover listeners em tempo real seria um pesadelo, especialmente se a adição e remoção de código se dá em diferentes partes da aplicação — o que é bastante comum. A melhor solução é adicionar um listener de eventos para o pai, o elemento <ul>
! Mas, se você adicionar o ouvinte de eventos para o pai, como vai saber qual elemento foi clicado?
Simples: quando o evento borbulha pra cima (bubbles up) até o elemento <ul>
, é possível verificar a propriedade target
para obter a referência sobre o nó que foi clicado. Aqui está um trecho muito básico JavaScript que ilustra a delegação de evento:
1 2 3 4 5 6 7 8 9 |
// Pega o elemento e adiciona um listener para click document.querySelector( '#parent-list' ).addEventListener( 'click', function( e ) { // e.target é o elemento clicado // se ele for um item de lista if ( e.target && e.target.nodeName == 'LI' ) { // Item da lista encontrado! Mostrando o ID! console.log( 'Item ', e.target.id.replace( 'post-', ''), ' foi clicado!' ); } }, false); |
Começa-se por adicionar um listener de click
no elemento pai. Quando este listener é acionado, verifica-se o elemento do evento para garantir que ele é o tipo de elemento a reagir. Se é um elemento <li>
, bum: tem-se o que é preciso; se não é um elemento <li>
, o evento pode ser ignorado.
Para fixar, partamos para outro exemplo, dessa vez com uma div
com muitos filhos, mas o que realmente importa é um elemento <a>
com a classe classA
. Como você faria? Qual seria o código para, dentre todos os nós-filho dentro desta div
possíveis de serem clicados, saber precisamente quando o que tem determinada classe o foi? Obviamente, identificando se o elemento clicado em questão possui tal classe:
1 2 3 4 5 6 7 |
// Pega o elemento e adiciona um listener para click document.querySelector( '#myDiv' ).addEventListener( 'click', function( e ) { // e.target é o elemento clicado if ( e.target && e.target.classList.contains( 'classA' ) ) { console.log( 'Link clicado!' ); } }, false); |
Simples, hã? ;-)
Conclusão sobre Delegação de Evento (ou Events Delegation)
A maioria das bibliotecas JavaScript, como jQuery, já possuem delegação de evento para se trabalhar. Então, mesmo que não se esteja trabalhando com JavaScript puro, em casos em que é preciso adicionar muitos eventos para elementos, sempre que possível use delegação de eventos.
Quando projeto pedir e/ou for do seu gosto pessoal (ou da equipe) trabalhar com vanilla JavaScript, agora você já sabe como lidar com Delegação de Eventos. É quase tão fácil quanto ao usar bibliotecas JS e, na quase totalidade dos casos, bem mais performático!