Eventstroom
Home

Eventstroom

Eventstroom

Wanneer een gebeurtenis wordt aangeroepen, stroomt de gebeurtenis door de DOM en worden dezelfde gebeurtenissen afgevuurd op andere knooppunten en JavaScript-objecten. De gebeurtenisstroom kan worden geprogrammeerd als:

  1. een capture-fase (dat wil zeggen, vanaf de DOM boomstam naar de takken) of
  2. een bubbling-fase of terugkoppelfase (dat wil zeggen, vanaf de DOM boomtakken naar de boomstam, of
  3. beide;

Beschrijving

Wanneer je klikt op de anker-tag, stroomt de klikgebeurtenis naar beneden in de boomstructuur van het document. Een keer aangekomen op het element die de klikgebeurtenis heeft afgevuurd maakt het klikevent rechtsomkeer en stroom terug naar boven naar het moederelement.

capture- en bubbling-fase

Als je op een dom element klikt begint de capture bij het moederelement window, stroomt door naar document, dan naar html, dan naar body en dan naar het eerste element in het body element en zo verder naar beneden in de DOM boomstructuur. Dat eerste naar beneden stromen heet de "capture-fase".

Het tweede naar boven stromen heet de terugkoppelfase of bubbling-fase. De volgende afbeelding moet dit verduidelijken:

JS - eventstroom
JS - eventstroom

Als je op de anker-tag klikt, berekent de DOM het capture-pad en vuurt de capture-fase event handlers af van het root document, body, div en a. Dan maakt het rechtsomkeer en vuurt alle events handlers van de bubbling-fase af in de omgekeerde volgorde van de capture-fase.

Zodra de event tot de bovenkant van de DOM is opgeborreld, wordt het standaardgedrag van de browser uitgevoerd. In het geval van een anker-tag, wordt de gebruiker omgeleid naar een andere pagina.

Je moet goed begrijpen dat de events dit pad doorheen de betrokken elementen op en neer volgen. De twee fasen kunnen elk een afzonderlijke verzameling van event handlers hebben op elk knooppunt van in het pad.

Het pad en de volgorde waarin het event de bovenliggende keten doorloopt wordt bepaald voordat er ook maar één event handler wordt afgevuurd. Dit betekent dat het wijzigen van de elementen binnen een event handler geen invloed meer heeft op welke event handlers van welke elementen afgevuurd worden. Als bijvoorbeeld event handler een element zijn bovenliggende element verwijderd en zichzelf toevoegt aan het onderliggende element, zal de event handler van het verwijderde element toch nog worden afgevuurd.

Om het pad te illustreren geven we het volgende voorbeeld. In het onload event van de pagina voeren we volgende code uit.

HTML

klik<div>
  hier voor div target<br />
  <a href="#">en hier voor a target</a>
</div>

CSS

div {
color: red;
text-decoration: underline;
cursor: pointer
}

JS

var eventstream = function() {
  //1 capture phase
  window.addEventListener('click',
    function() {
      console.log('1: capture fase window');
    }, true);
  //2 capture phase
  document.addEventListener('click',
    function() {
      console.log('2: capture fase document');
    }, true);
  //3 capture phase voor html element
  document.documentElement.addEventListener('click',
    function() {
      console.log('3: capture fase html');
    }, true);
  //4 capture phase
  document.body.addEventListener('click',
    function() {
      console.log('4: capture fase body');
    }, true);
  //5 capture phase
  document.querySelector('div').addEventListener('click',
    function() {
      console.log('5: capture fase div');
    }, true);
  //6 target phase occurs during capture phase
  document.querySelector('a').addEventListener('click',
    function() {
      console.log('6: target fase a');
    }, true);
  //7 target phase occurs during bubbling phase
  document.querySelector('a').addEventListener('click',
    function() {
      console.log('7: target fase a');
    }, false);
  //8 bubbling phase
  document.querySelector('div').addEventListener('click',
    function() {
      console.log('8: bubbling fase div');
    }, false);
  //9 bubbling phase
  document.body.addEventListener('click',
    function() {
      console.log('9: bubbling fase body');
    }, false);
  //10 bubbling phase
  document.documentElement.addEventListener('click',
    function() {
      console.log('10: bubbling fase html');
    }, false);
  //11 bubbling phase
  document.addEventListener('click',
    function() {
      console.log('11: bubbling fase document');
    }, false);
  //12 bubbling phase
  window.addEventListener('click',
    function() {
      console.log('12: bubbling fase window')
    }, false);
}
window.onload = eventstream;

Als we op het anker element klikken zien we dat de events van alle noden op het pad, zowel tijdens de capture, target als bubbling fasen, afgevuurd worden:

"1: capture fase window"
"2: capture fase document"
"3: capture fase html"
"4: capture fase body"
"5: capture fase div"
"6: target fase a"
"7: target fase a"
"8: bubbling fase div"
"9: bubbling fase body"
"10: bubbling fase html"
"11: bubbling fase document"
"12: bubbling fase window"

Het zelfde gebeurd als op de div klikken. Maar het ankerelement wordt deze keer niet in het pad opgenomen:

"1: capture fase window"
"2: capture fase document"
"3: capture fase html"
"4: capture fase body"
"5: capture fase div"
"8: bubbling fase div"
"9: bubbling fase body"
"10: bubbling fase html"
"11: bubbling fase document"
"12: bubbling fase window"

Je kan deze code uittesten op CodePen. Klik rechtsboven op Edit on CodePen en open het console venster (links onderaan) om deze oefening te kunnen volgen.

Bronnen

Giulio Mainardi, What Is Event Bubbling in JavaScript? Event Propagation Explained, May 24, 2017

Brian Moschel, A crash course in how DOM events work, October 01, 2010

JI
2017-05-27 10:43:36