Propagação de Eventos em JavaScript
Quando clicamos em um elemento na página, um evento de clique é disparado e esse evento pode se propagar de elemento para elemento. Por exemplo, se clicarmos em um bloco div
, também estamos clicando no elemento body
que contém esse div
. Isso é chamado de propagação de evento.
Existem várias formas de propagação de eventos:
Eventos de bolha (bubbling)
: o evento se propaga para cima na árvore DOM, dos nós filhos para os nós pais.Eventos de captura (capturing)
: o evento se propaga para baixo na árvore DOM, dos nós pais para os nós filhos, até alcançar o elemento onde o evento foi disparado.
Eventos de Bolha
Consideremos eventos de bolha(bubbling), que se propagam para cima na árvore DOM. Suponha que temos a seguinte página web:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Programício</title>
<style>
#blueRect {
width: 100px;
height: 100px;
background-color: blue;
}
#redRect {
position: relative;
top: 25px;
left: 25px;
width: 50px;
height: 50px;
background-color: red;
}
</style>
</head>
<body>
<div id="blueRect">
<div id="redRect"></div>
</div>
<script>
const redRect = document.getElementById("redRect");
redRect.addEventListener("click", () => console.log("Evento no redRect"));
const blueRect = document.getElementById("blueRect");
blueRect.addEventListener("click", () => console.log("Evento no blueRect"));
document.body.addEventListener("click", () => console.log("Evento no body"));
</script>
</body>
</html>
Se clicarmos no div
interno (vermelho), o evento irá se propagar para o div
pai e, em seguida, para o elemento body
:
Controle dos Eventos de Bolha
É importante notar que esse comportamento nem sempre é desejado. Nesse caso, podemos interromper a propagação do evento usando o método stopPropagation()
do objeto Event
:
const redRect = document.getElementById("redRect");
redRect.addEventListener("click", function (e) {
console.log("Evento no redRect");
e.stopPropagation();
});
Como resultado, o evento será tratado apenas pelo manipulador do redRect
.
No entanto, stopPropagation()
tem uma limitação: ele impede a execução de outros manipuladores de eventos no mesmo elemento. Para evitar isso, podemos usar stopImmediatePropagation()
:
const redRect = document.getElementById("redRect");
function handler1(e) {
console.log("handler1: Evento no redRect");
e.stopImmediatePropagation();
}
function handler2(e) {
console.log("handler2: Evento no redRect");
}
redRect.addEventListener("click", handler1);
redRect.addEventListener("click", handler2);
Eventos de Captura
Os eventos também podem ser de captura(capturing). Para utilizá-los, passamos um valor lógico true como terceiro parâmetro opcional no método addEventListener()
. O valor true
indica que o evento será de captura. Por padrão, todos os eventos são de bolha.
Modificando o código JavaScript da mesma página, teremos:
const redRect = document.getElementById("redRect");
redRect.addEventListener(
"click",
function () {
console.log("Evento no redRect");
},
true
);
const blueRect = document.getElementById("blueRect");
blueRect.addEventListener(
"click",
function () {
console.log("Evento no blueRect");
},
true
);
document.body.addEventListener(
"click",
function () {
console.log("Evento no body");
},
true
);
Agora, os eventos se propagarão na ordem inversa: