JavaScript bubbling e capturing
Publicado em: 2014-09-23 — 24.859 visualizacoes
Introdução
Elementos da marcação HTML podem ser aninhados uns dentro de outros, criando-se uma cadeia de elementos-filhos e seus elementos-ancestrais. Neste cenário, quando se atrela um evento JavaScript (por exemplo: o evento clicar) a um determinado elemento E do DOM ele, evento, será disparado mesmo que o clique ocorre em um elemento-filho de E.
O nome usado na terminologia JavaScript para descrever esse efeito é event bubbling. Bubbling em tradução livre significa borbulhante, assim em linguagem não técnica podemos dizer que eventos JavaScript borbulham, no sentido de que são disparados por ação em elementos descendentes do elemento a que são atrelados.
No exemplo mostrado a seguir o evento clique dispara o alerta mesmo quando o clique ocorre nos elementos em
ou code
, embora ele, evento, tenha sido atrelado ao elemento div
.
<div onclick="alert('Evento disparado!')"> <em>Nesta área experimente clicar no elemento <code>EM</code> aninhado não clicando no <code>DIV</code> e observe que há o disparo do alerta.</em> </div>
EM
aninhado não clicando no DIV
e observe que há o disparo do alerta.
Esse efeito ocorre porque o evento “borbulha” bubbles do elemento mais aninhado para seu elemento-ancestral.
Bubbling
O princípio fundamental do efeito bubbling diz o seguinte:
Depois que um evento é disparado no elemento mais distante de uma cadeia aninhada do DOM ele é disparado em seus elementos ancestrais na ordem crescente de aninhamento.
Observe um exemplo com três elementos div
aninhados:
<!DOCTYPE HTML> <html> <body> <link type="text/css" rel="stylesheet" href="example.css"> <div class="d1">1 <!-- ancestral mais alto --> <div class="d2">2 <div class="d3">3 <!-- descendente mais baixo --> </div> </div> </div> </body> </html>
O efeito bubbling da JavaScript faz com que um clique no no div 3 dispare o evento a ele atrelado primeiro no elemento descendente mais baixo 3 (também chamado de target), depois no elemento 2 e finalmente no elemento 1.
um clique no no div 2 dispara o evento a ele atrelado primeiro no elemento 2 (também chamado de target) e depois no elemento 1.
um clique no no div 1 dispara o evento a ele atrelado (também chamado de target) e nada mais.
A ordem de disparo é chamada de bubbling order, pois o evento “borbulha” do elemento descendente mais baixo para seus ancestrais tal como ocorre com uma bolha de ar na água.
O exemplo mostrado a seguir é interativo e demonstra visualmente o efeito bubble. Clique os divs:
Observe a seguir os código do exemplo:
HTML
<div class="d1">1 <div class="d2">2 <div class="d3">3 </div> </div> </div>
CSS
<style> .d1 { background-color: green; position: relative; width: 150px; height: 150px; text-align: center; cursor: pointer; } .d2 { background-color: blue; position: absolute; top: 25px; left: 25px; width: 100px; height: 100px; } .d3 { background-color: red; position: absolute; top: 25px; left: 25px; width: 50px; height: 50px; line-height: 50px; } </style>
JavaScript
<script> var divs = document.getElementsByTagName('div') for(var i=0; i<divs.length; i++) { divs[i].onclick = function(e) { e = e || event var target = e.target || e.srcElement this.style.backgroundColor='yellow' alert("target = "+target.className+", this="+this.className) this.style.backgroundColor = '' } } </script>
this e event.target
O elemento descendente mais baixo que dispara o evento é chamado de target ou elemento originário.
O navegador Internet Explorer define para target a propriedade srcElement
e os navegadores em conformidade com o W3C definem a propriedade event.target
.
O código JavaScript cross-browser é mostrado a seguir:
var target = event.target || event.srcElement
Handlers (ações disparadas por eventos) em ancestrais:
- event.target/srcElement – refere-se ao elemento que origina o evento.
- this – refere-se ao elemento corrente, aquele para o qual o evento “borbulhou” ou ainda, aquele que dispara o handler.
No exemplo interativo mostrado a seguir para cada elemento div
foi definido o atributo onclick
para disparar um handler cuja saída mostra quem é target e quem é this.
Clique em um div
e observe o seguinte:
- target permanece constante durante todo o processo de bubbling,
- this modifica-se e é destacado em cor diferente.
Observe a seguir os código do exemplo:
HTML
<div class="d1">1 <div class="d2">2 <div class="d3">3 </div> </div> </div>
CSS
<style> .d1 { background-color: green; position: relative; width: 150px; height: 150px; text-align: center; cursor: pointer; } .d2 { background-color: blue; position: absolute; top: 25px; left: 25px; width: 100px; height: 100px; } .d3 { background-color: red; position: absolute; top: 25px; left: 25px; width: 50px; height: 50px; line-height: 50px; } </style>
JavaScript
<script> var divs = document.getElementsByTagName('div') for(var i=0; i<divs.length; i++) { divs[i].onclick = function(e) { e = e || event var target = e.target || e.srcElement this.style.backgroundColor='yellow' alert("target = "+target.className+", this="+this.className) this.style.backgroundColor = '' } } </script>
Em navegadores em conformidade com o W3C this também pode ser obtido com uso de event.currentTarget
.
Cancelar bubbling
Vimos que o efeito bubbling percorre elementos aninhados no DOM de baixo para cima (do elemento filho para seus ancestrais).
É possível interromper o efeito bubbling antes que ele percorra todos os elementos aninhados.
O código para interromper o efeito em navegadores em conformidade com o W3C é mostrado a seguir:
event.stopPropagation()
Para os IE<9:
event.cancelBubble = true
E, finalmente o código cross-browser:
element.onclick = function(event) { event = event || window.event // cross-browser event if (event.stopPropagation) { // opção para poadrões W3C event.stopPropagation() } else { // opção para IE event.cancelBubble = true } }
Simplificação do código cross-browser:
event.stopPropagation ? event.stopPropagation() : (event.cancelBubble=true)
Se a um elemento for atrelado vários handlers disparados pelo mesmo evento, os handelers serão independentes..
Por exemplo: se em um link existerem dois handelers disparados por click, interromper o efeito bubbling em um dos handelers não interrompe no outro. O navegador não tem qualquer compromisso com a ordem de disparo dos handelers.
Capturing
En todos os navegadores, exceto nos IE<9 os eventos são processados em dois estágios.
No primeiro estágio o evento percorre a cadeia aninhada de cima para baixo (dos elementos ancestrais para os elementos descendentes) – este estágio é chamado capturing. No outro estágio ocorre o efeito bubbles como estudado. Este comportamento é padronizado pelas especificações do W3C.
Segundo esse modelo o comportamento do evento é:
- Captures para baixo – na direção 1 -> 2 -> 3.
- Bubbles para cima – na direção 3 -> 2 -> 1.
Todos os métodos de manipulação de eventos simplesmente ignoram a fase caputuring. Para que o evento ocorra na fase capturing declaramos o último argumento método addEventListener
como sendo true.
Observe o código mostrado a seguir:
elem.addEventListener( type, handler, phase )
- phase = true
- O handler dispara na fase capturing.
- phase = false
- O handler dispara na fase bubbling.
Clique em um dos divs mostrados a seguir para constatar o efeito capturing em ação (exceto IE<9):
A ordem deverá ser 1 -> 2 -> 3.
Observe o código JavaScript desse exemplo:
var divs = document.getElementsByTagName('div') for(var i=0; i<divs.length; i++) { divs[i].addEventListener("click", highlightThis, true) }
Na prática a fase capturing raramente é usada, mas
existem eventos que não “borbulham”, mas honram o efeito capturing. Por exemplo: onfocus
e onblur
.
No exemplo mostrado a seguir atrelamos handlers a ambos os estágios.
Clique em um dos divs mostrados a seguir para constatar a ordem de processamento dos eventos (exceto IE<9):
A ordem deverá ser 1 -> 2 -> 3 -> 3 -> 2 -> 1.
Observe o código JavaScript desse exemplo:
var divs = document.getElementsByTagName('div') for(var i=0; i<divs.length; i++) { divs[i].addEventListener("click", highlightThis, true) divs[i].addEventListener("click", highlightThis, false) }
Sumário
- Eventos primeiramente são captured para baixo e depois bubble para cima. Os IE<9 honram apenas o efeito bubble.
- Todos os handlers disparam no efeito bubbling exceto quando o último argumento do método
addEventListener
for declarado true, aliás essa é a única maneira de disparar o evento na fase capturing. - Bubbling e capturing podem ser cancelados no IE com uso de
event.cancelBubble=true
(IE) ou comevent.stopPropagation()
para os demais navegadores.
Crédito: http://learn.javascript.ru/
Publicado segundo os termos da licença CC BY-NC-SA.
Desenvolvimento com Padrões Web? Adquira os livros do Maujor
Visite o site dos livros.
Esta matéria foi publicada em: 2014-09-23 (terça-feira). Subscreva o feed RSS 2.0 para comentários.
Comente abaixo, ou link para https://www.maujor.com/blog/2014/09/23/javascript-bubbling-e-capturing/trackback no seu site.
Seu blog é excelente. Estou aprendendo um pouco sobre programação e a sua página é uma de minhas fontes principais para tirar duvidas.
Parabéns! ótimas dicas, estou começando a apreender um pouco sobre programação, tentando melhorar meu site! obrigado, dicas bem uteis!
Seu blog é excelente. Estou aprendendo um pouco sobre programação e a sua página é uma de minhas fontes principais para tirar duvidas.
Estou muito grato pelo que você compartilhe este artigo, eu incluído na categoria de iniciantes para jogar assuntos javascrip ou html, onde eu poderia aprender ?? se for permitido , existe um site on-line para aprender o básico sobre html ?? mendigar em responder , estou muito ansioso para ser capaz de dominar as ligações do HTML ou qualquer javascrip , obrigado
Video Bokep
Assim como o Cesar não fico comentando, mas hj concordo com ele… estou aprendendo com o livro Guia Definitivo e sou iniciante, mas sempre vejo seus conteúdo quando preciso. xD
Muito bom! Sou Programador Web e sempre acompanho os posts deste blog sem falar no site do maujor.com que para mim é essencial uma passada por lá mesmo que seja rápida! Aqui sempre há algo de novo e interessante para se aprender. Eu sempre que posso passo por aqui mas somente desta vez resolvi comentar. Este post me orientou bastante em trabalhos que eu estava desenvolvendo. Este site é e sempre será um incentivo para eu continuar crescendo e aprendendo constantemente. Parabéns a todos pela rica iniciativa de partilhar conhecimentos de qualidade de forma didática, clara e objetiva!!!
Olá, adorei as dicas, at+
Tita Carré
Excelente post! Eu mesmo já tive essa dúvida e sempre vejo gente procurando saber: como cancelar evento de clique atrelado a um elemento pai durante o clique de um elemento filho… Enfim, esse artigo esclarece bem a questão.