Guia básico para adicionar eventos em Javascript e despertar a interatividade
Tags: javascr, addeventlistener, events, webdev
Published: 2023-06-14 22:36:56

## Veja 3 formas simples de adicionar eventos Javascript, descobrir o elemento clicado, tecla pressionada, valor do input, entre outros dados.
 
Programação Orientada a Eventos...
 
**Eventos são *coisas* que acontecem quando o usuário interage com um site**. Achou estranho o termo "coisas"? Pois é assim mesmo que a [W3C define os eventos](https://www.w3schools.com/js/js_events.asp). 😛 
 
Eles podem ser de vários tipos:
 
- Mouse: clique, scroll, clique duplo
- Teclado: pressionar uma tecla, soltar uma tecla
- Página: terminar de pintar os elementos HTML, finalizar o carregamento completo da página
- Entre outros
 
Nesse post você vai ver muita coisa sobre eventos:
 
- Adicionar um evento
- Adicionar mais de um evento
- Substituir
- Remover
- Como ter acesso às informações do evento
 
Assim que você cria um, é preciso informar uma função callback. Ela irá executar assim que o evento disparar.
 
Até o momento aprendi 3 formas de adicionar eventos em Javascript.
 
## Adicionar evento Javascript pelo atributo do elemento HTML
 
Uma dica: evite essa forma.
 
Eu evito ela quando trabalho com Javascript puro, sem framework:
 
```html
<button class="button" onclick="myFunction()">
  OK!
</button>
```
 
```javascript
function myFunction() {
  console.log('Clicou no botão "OK!"');
}
```
 
O motivo de não gostar muito desse método é que a declaração da função fica no arquivo Javascript, enquanto a execução fica no HTML.
 
Prefiro deixar tudo no arquivo Javascript, e essa será a forma que você vai ver agora.
 
## Adicionar evento Javascript com o método addEventListener
 
Essa forma é a "oficial".
 
Acredito que a maioria das pessoas usem ela:
 
```html
<button class="button">
  OK!
</button>
```
 
```javascript
const button = document.querySelector('.button');

button.addEventListener('click', function() {
  console.log('Clicou no botão "OK!"');
});
```
 
Costumo usar essa forma para adicionar mais de um eventos no mesmo elemento. Exemplo:
 
- `document.addEventListener()`
- `window.addEventListener()`
 
`A terceira forma que vou ensinar é bem parecida com essa porém um pouco mais simples. Veja abaixo.`
 
## Adicionar evento Javascript com a propriedade on do elemento HTML
 
Essa forma é bastante parecida com a anterior.
 
Se eu quiser adicionar um evento de clique em um botão, uso a propriedade `onclick`:
 
```html
<button class="button">
  OK!
</button>
```
 
```javascript
const button = document.querySelector('.button');

button.onclick = function(event) {
  console.log('Clicou no botão "OK!"');
});
```
 
A diferença é onde você informa a função callback. Se usar o atributo, ela é o valor dele; caso use o `addEventListener`, ela será um argumento da função.
 
**Prefiro usar esse método quando vou aplicar um evento em um elemento que recebe um evento só.**
 
Caso precise fazer isso com outro tipo de evento, basta usar esse atributo com `on` na frente:
 
- `onmouseenter`
- `onmouseleave`
- `onmouseover` .
 
Essas são as formas mais comuns de adicionar um evento em Javascript.
 
Mas se tem tantas formas, qual é a diferença entre elas? Talvez você já tenha se perguntado... até hoje.
 
## Diferença entre o método addEventListener e o atributo on
 
As principais diferença entre elas são duas:
 
- A forma como você remove os eventos
- Como acontece a substituição ou adição de novos eventos
 
### Remoção de evento
 
Remover um evento que você adicionou com o `addEventListener` é bem fácil. Use praticamente o mesmo código, porém troque `addEventListener` por `removeEventListener`:
 
```javascript
const button = document.querySelector('.button');

function callbackFunction() {
  console.log('Clicou no botão "OK!"');
}

// Adicionar evento
button.addEventListener('click', callbackFunction);

// Remover evento
button.removeEventListener('click', callbackFunction);
```
 
Perceba que no código acima eu declarei a função callback antes de adicionar os eventos. Isso porque no `removeEventListener` eu preciso informar exatamente qual função quero remover.
 
Caso eu declarasse a função dentro dos parênteses do `addEventListener()`, ela só existiria ali dentro. E assim, seria impossível referenciar ela de fora para remover.
 
Então se você adicionar um evento que talvez precise ser removido no futuro, use essa estratégia.
 
Se usar o `element.onclick = function() {}`, basta fazer uma nova atribuição, porém agora com o valor `null`:
 
```javascript
const button = document.querySelector('.button');

// Adicionar evento
button.onclick = function(event) {
  console.log('Clicou no botão "OK!"');
});

// Remover evento
button.onclick = null;
```
 
Veja agora a outra diferença desses dois modos de adicionar eventos em Javascript.
 
### Substituição ou adição de evento
 
O método `addEventListener` permite que o mesmo elemento possa receber múltiplos eventos.
 
**Está no próprio nome: ele *adiciona (add) um escutador (listener) de eventos (event)*. Isso vale também para eventos do mesmo tipo. Assim, um botão pode ter mais de um evento de clique.**
 
Por outro lado, se você usar a propriedade `onclick`, o segundo evento irá sobrescrever o primeiro.
 
```javascript
button.onclick = function() {
  alert('primeiro clique');
}

button.onclick = function() { // remove o evento acima
  alert('segundo clique');
}
```
 
Se for a primeira vez que você vê as diferenças entre o `addEventListener` e o atributo `on...`, pode parecer confuso. Para evitar maiores problemas, use sempre o `addEventListener`.
 
Legal, você já sabe como disparar eventos em Javascript. Mas o que fazer com eles? Pense que a cada disparo, você recebe diversas informações desse evento. Veja agora as principais.
 
## As informações do evento
 
É aqui que a magia acontece.
 
Como você viu ao longo desse post, todo ouvinte de evento recebe uma função, e ela executa assim que o evento dispara.
 
Essa função pode receber como parâmetro um objeto com as informações do evento. Chame-o como quiser:
 
- `event`
- `evento`
- `infosDoEvento`
- Até de `batata`, só peço que não chame de `e` (por favor)
 
```javascript
elemento.addEventListener('tipoDeEvento', function(batata) {
  console.log(batata);
});
```
 
Para facilitar a explicação, vou chamar sempre de `event`.
 
**Esse objeto possui as informações do evento que acabou de disparar**. E claro, as informações dependem do tipo de evento.
 
Veja algumas propriedades mais comuns:
 
### Elemento HTML alvo do evento
 
Arrisco dizer que esse é o mais usado.
 
Use o `event.target` quando você quer descobrir qual é o **elemento que disparou o evento**:
 
```html
<button class="button">OK!</button>
```
 
```javascript
const button = document.querySelector('.button');

button.addEventListener('click', function(event) {
  console.log(event.target); // <button class="button">OK!</button>
});
```
 
Essa propriedade está disponível não apenas para eventos de clique, mas também outros eventos comuns de mouse. Quando o ponteiro do mouse:
 
- Passa sobre um elemento: `mouseover`
- Sai de cima de um elemento: `mouseleave`
- Se move sobre um elemento: `mousemove`. Dispara a cada pixel que o ponteiro se desloca
 
Porém, existe uma pegadinha no `event.target`. Veja esse outro exemplo com um `span` dentro do `button`:
 
```html
<button class="button">
  <span>OK!</span>
</button>
```
 
```javascript
const button = document.querySelector('.button');

button.addEventListener('click', function(event) {
  console.log(event.target); // ???
});
```
 
Nessa situação, `event.target` pode apontar tanto para o `button`, quanto para o `span`. Tudo depende de qual região do botão você clicou.
 
Se foi em cima do texto "OK!", será o `span`. Se o clique foi mais para a borda, então será o `button`.
 
E como ter certeza de quem é o alvo do evento? A solução disso está no próximo capítulo...
 
### Elemento HTML ligado ao event listener
 
É quase igual ao anterior.
 
Porém, em vez de receber o elemento que o usuário clicou, **você recebe aquele que teve o evento atrelado a ele**.
 
Para isso, use `event.currentTarget`:
 
```html
<button class="button">
  <span>OK!</span>
</button>
```
 
```javascript
const button = document.querySelector('.button');

button.addEventListener('click', function(event) {
  console.log(event.currentTarget); // Agora com certeza será sempre o button
});
```
 
Há um tempo, eu escrevi um post sobre a [diferença desses dois targets](https://demenezes.dev/posts/diferenca-entre-event-target-e-event-currenttarget/).
 
Assim como a propriedade anterior (`event.target`), essa daqui também não é exclusiva do evento de clique.
 
### Tecla do teclado que o usuário pressionou
 
A primeira vez que fiz isso, me senti meio hacker.
 
```javascript
document.addEventListener('keydown', function(event) {
  console.log(event.altKey); // true ou false
  console.log(event.ctrlKey); // true ou false
  console.log(event.shiftKey); // true ou false
  console.log(event.key); // O nome da tecla que o usuário pressionou
});
```
 
Quando você usa eventos de teclado, como o `onkeydown` e `onkeyup`, as informações do evento são as mesmas. Entre elas, as mais interessantes são:
 
- Descobrir qual foi a tecla que o usuário pressionou (`event.key`)
- Descobrir se usuário segurou `ctrl`, `alt` e/ou `shift` no momento do `keydown` ou `keyup`
 
### Valor de um campo de input
 
Isso é super útil para quando você precisa trabalhar com um valor em tempo real:
 
![uma tela com um texto que é pego pelo conteúdp de uma input em tempo real](https://demenezes.dev/_next/image/?url=https%3A%2F%2Fwww.datocms-assets.com%2F64896%2F1686687595-input-tempo-real.png%3Fauto%3Dformat&w=3840&q=75)
 
Existem três eventos para pegar essa informação, e cada um tem suas características:
 
- `onchange`: ocorre quando o usuário muda o valor da caixa de `select`
- `oninput`: ocorre quando o usuário digita uum caractere no `input`
- `onblur`: ocorre quando o foco muda de um elemento para o outro. Funciona tanto com `input` quanto com qualquer element focalizável
 
Para entender melhor como o focus funciona, eu escrevi esse post sobre o [focus em HTML, CSS e Javascript](https://demenezes.dev/posts/focus-em-elementos-html-css-javascript/).
 
Mesmo assim, o `onchange` também funciona com o elemento `input`, e seu comportamento é igual ao do `onblur`. Além disso, o `oninput` também funciona com o elemento `select`.
 
E para finalizar essa explicação, assim que o evento dispara, basta pegar o valor do alvo do evento:
 
```javascript
const input = document.querySelector('.input');

input.addEventListener('change', function(event) {
  console.log(event.target.value);
});

input.addEventListener('input', function(event) {
  console.log(event.target.value);
});

input.addEventListener('blur', function(event) {
  console.log(event.target.value);
});
```
 
### Posição da barra de rolagem da página
 
Essa é outra informação muito importante.
 
Se sua funcionalidade depende do scroll da página, use os eventos `onscroll` e `onwheel`. A diferença entre eles é muito pequena:
 
- `onscroll`: o evento dispara quando a barra de rolagem da página se move. Esse evento depende da página
- `onwheel`: o evento dispara quando o usuário usa o scroll do mouse, touchpad ou outro dispositivo. Esse evento depende do hardware do usuário
 
A melhor forma de entender a diferença é:
 
1. Adicione os dois eventos na mesma página
2. Role a página de rolagem até o final ou até o topo
3. Durante esse trajeto, você irá perceber que os dois eventos disparam
4. Quando atingir o início ou fim da página e continuar tentando avançar, apenas o `onwheel` irá disparar
5. O `onscroll` dispara apenas enquanto a página não chegou no seu limite
 
Você pode adicionar esse evento na página inteira (`document`), ou em um elemento com scroll interno:
 
```javascript
document.addEventListener('scroll', function(event) {
  console.log('scroll', event);
});

document.addEventListener('wheel', function(event) {
  console.log('wheel', event);
});
```
 
Assim que o evento disparar, você pode descobrir qual é a posição da barra de rolagem na tela. Basta pegar o valor de:
 
- `window.pageXOffset`: a posição da barra de rolagem horizontal
- `window.pageYOffset`: a posição da barra de rolagem vertical
 
**Perceba que esses valores estão dentro do objeto global `window` e não em `event`. Logo, você também tem acesso a eles fora dos eventos de `onscroll` e `onwheel`**.
 
Uma ótima forma de usar os eventos de scroll, é criar o efeito de lazyload. Nele, o navegador baixa as imagens apenas quando se aproximam da área de visualização da tela, e não no carregamento da página.
 
Você pode ver a aplicação disso nesse post onde mostrei [como criar o efeito de lazyload](https://demenezes.dev/posts/como-fazer-lazyload/).
 
## Callback
 
Você pode adicionar eventos em Javascript de três formas:
 
- Pelo atributo HTML
- Pelo método `addEventListener` do Javascript
- Ou pela propriedade `on...` do elemento HTML
 
As duas últimas opções são bem parecidas, mas têm diferenças quanto a remover ou substituir o evento.
 
Use o argumento da função callback para pegar informações do evento que disparou. Essas informações dependem do tipo de evento, mas as mais comuns são:
 
- O elemento HTML que disparou o evento
- O elemento HTML ligado ao event listener
- A tecla que o usuário pressionou
- O valor do campo de input
- A posição da barra de rolagem
 
Esse tipo de conteúdo eu gostaria de ter lido quando comecei a estudar Javascript. Mas saiba que fui descobrir como usar o `event.target` apenas na minha primeira experiência como dev. Foi uma descoberta que explodiu minha cabeça.
 
Então espero que esse post tenha esclarecido para você algumas coisas sobre eventos em Javascript.