Shortcut
Em alguns momentos, você precisará trocar o event.target
pelo event.currentTarget
.
Se você conhece o event.target
, é tentador usar ele em situações como essa.
Imagine que você tem um ecommerce, e essa é sua página de produto:
Nela, o usuário vê a imagem de destaque à esquerda, e as minuatura do produto à direita. E digamos que você queira mudar a imagem de destaque, a cada clique nas miniaturas. Para isso, é preciso descobrir em qual cor o usuário clicou.
Infelizmente, usar o event.target
aqui pode causar alguns probleminhas.
Veja o que pode acontecer.
O problema do event.target
Abaixo está a seção com as miniaturas das cores:
<button class="color-button" data-color="blue">
<img src="blue.png" />
</button>
<button class="color-button" data-color="gray">
<img src="gray.png" />
</button>
<button class="color-button" data-color="red">
<img src="red.png" />
</button>
<button class="color-button" data-color="green">
<img src="green.png" />
</button>
Perceba que cada botão possui um atributo data-color
com a sua cor. Isso será importante daqui a pouco.
Agora veja como fica o script para adicionar um evento de clique nesses botões:
// Pegar os botões
const colorButtons = document.querySelectorAll('.color-button');
// Iterar por eles, e adicionar um evento
// que muda a foto principal com base na cor
colorButtons.forEach(function(button) {
button.addEventListener('click', changePictureByColor);
// Criar a função do evento
function changePictureByColor(event) {
// ...
}
Até aqui tudo bem.
Agora, na função changePictureByColor
você precisa descobrir qual foi a cor clicada.
Já que a cor está no atributo data-color
de cada botão, basta pegar o seu valor:
function changePictureByColor(event) {
const clickedColor = event.target.getAttribute('data-color');
// ...
}
Agora com a variável clickedColor
em mãos, você pode seguir com a função e trocar a imagem em destaque.
Certo? Errado!
A sua função começa a estourar erros e mais erros... E após muito suor, você descobre que a variável clickedColor
retorna null
. Mas como?!
Como obter o elemento HTML alvo do evento
Console, eu escolho você!
Você então invoca uma chuva de console.log
até descobrir que event.target
não aponta para o botão. E sim para a imagem dentro do botão. E como a imagem não tem um atributo data-color
, o caos começa.
Veja algumas formas de corrigir isso.
Adicionar o atributo data-color na imagem
Essa é a solução que gosto menos.
<button class="color-button">
<img src="blue.png" data-color="blue" />
</button>
<button class="color-button">
<img src="gray.png" data-color="gray" />
</button>
<button class="color-button">
<img src="red.png" data-color="red" />
</button>
<button class="color-button">
<img src="green.png" data-color="green" />
</button>
Isso porque, caso o usuário clique na pontinha do botão, ali onde a tag <img>
já não existe mais, o event.target
será o botão. E nesse caso, ele não possui o data-color
.
Outra opção é...
Adicionar o atributo data-color na imagem e no botão
Antes eu estava de brincadeira. ESSA SIM é a solução que gosto menos.
Alguns dos motivos são:
O dado fica repetido em mais de um lugar
Caso existam outros elementos dentro de
<button>
, todos eles precisariam do atributo.
Uma solução um pouco melhor (que usei por muito tempo) é...
Usar o método closest() do Javascript
Voltarei com o HTML original, com o data-color
no botão:
<button class="color-button" data-color="blue">
<img src="blue.png" />
</button>
<button class="color-button" data-color="gray">
<img src="gray.png" />
</button>
<button class="color-button" data-color="red">
<img src="red.png" />
</button>
<button class="color-button" data-color="green">
<img src="green.png" />
</button>
Agora vou adicionar algumas linhas na função, para garantir que peguei o botão:
function changePictureByColor(event) {
const clickedButton = event.target.closest('.color-button'); // pegar botão
const clickedColor = clickedButton.getAttribute('data-color'); // pegar cor
// ...
}
O método closest()
recebe um seletor e retorna o primeiro elemento que corresponda a esse seletor. Porém em vez de buscar na página inteira, o método sobe na árvore HTML.
Então quando executo event.target.closest('.color-button')
, os passos que a função closest()
executa são os seguintes:
event.target
(a imagem) possui a classecolor-button
? Não, então executa novamente com o elemento pai da imagem<button class="color-button">
possui a classecolor-button
? Sim, então retorna eleFim
Caso chegue até o elemento raiz <html>
e não encontre, retorna null
.
Assim, tenho a certeza de que agora peguei o botão. Agora posso pegar a cor clicada e prosseguir.
Usei essa solução por muito tempo me achando o máximo. Até descobrir que posso...
Usar event.currentTarget em vez de event.target
E só isso!
function changePictureByColor(event) {
const clickedColor = event.currentTarget.getAttribute('data-color');
// ...
}
Assim, a variável clickedColor
sempre vai receber a cor presente no atributo data-color
do botão.
Mas que magia aconteceu aqui?
O event.target
aponta para o elemento que dispara o evento, ou seja, aquele que cliquei de fato. Isso pode ser o próprio botão, ou qualquer elemento dentro dele, como a imagem. Assim, em cada clique, event.target
pode ser um elemento HTML diferente.
Já o event.currentTarget
aponta sempre para o mesmo elemento. Aquele que foi atribuído ao addEventListener
.
No exemplo do ecommerce que você acabou de ver, event.target
e event.currentTarget
apontam para elementos diferentes.
Callback
Como dito, a propriedade event.target
aponta para o elemento que disparou o evento.
Já o event.currentTarget
aponta para o elemento que possui o event listener associado a ele.
Fique atento para usar cada propriedade no momento certo.