Den skjulte nøkkelen til dynamiske nettinteraksjoner

Da jeg fortsatt lærte meg om nettutvikling, var en av de overraskende og spennende atferdene jeg møtte hendelsesboblende. Til å begynne med virket det uvanlig, men når du tenker på at hendelsen bobler, vil du se at det gir så mye mening. Som nettutvikler vil du garantert møte boblende hendelser. Så hva er det som bobler?

For å gi brukerne muligheten til å samhandle med nettsider, er JavaScript avhengig av hendelser. En hendelse refererer til hendelser eller handlinger som kan oppdages og reageres på av koden du skriver. Eksempler på hendelser inkluderer museklikk, tastetrykk og innsending av skjemaer, blant annet.

JavaScript bruker hendelseslyttere til å oppdage og svare på hendelser. En hendelseslytter er en funksjon som lytter etter eller venter på at en spesifikk hendelse skal skje på en side. For eksempel en klikkhendelse på en knapp. Når en hendelseslytter oppdager hendelsen den lytter etter, svarer den ved å utføre kode knyttet til hendelsen. Hele denne prosessen med å fange opp og svare på hendelser kalles hendelseshåndtering.

Tenk deg nå at vi har tre elementer på en side: en div, en span og en knapp. Knappeelementet er nestet inne i span-elementet, og span-elementet er nestet inne i div. En illustrasjon av dette er vist nedenfor:

Forutsatt at hvert av disse elementene har en hendelseslytter som lytter etter en klikkhendelse og skriver ut til konsollen når den klikkes, hva skjer når du klikker på knappen?

For å teste dette selv, lag en mappe, og i mappen oppretter du en HTML-fil som heter index.html, en CSS-fil som heter style.css, og en JavaScript-fil som heter app.js.

I HTML-filen legger du til følgende kode:

<!DOCTYPE html>
<html lang="en">

<head>
  <title>Event bubbling</title>
  <link rel="stylesheet" href="https://wilku.top/the-hidden-key-to-dynamic-web-interactions/style.css">
</head>

<body>
  <div>
    <span><button>Click Me!</button></span>
  </div>
  <script src="app.js"></script>
</body>

</html>

I CSS-filen legger du til følgende kode for å style div og span-elementet.

div {
  border: 2px solid black;
  background-color: orange;
  padding: 30px;
  width: 400px;
}

span {
  display: inline-block;
  background-color: cyan;
  height: 100px;
  width: 200px;
  margin: 10px;
  padding: 20px;
  border: 2px solid black;
}

I JavaScript-filen legger du til følgende kode, som legger til hendelseslyttere til div-, span- og knappelementene. Eventlistene lytter alle etter en klikkhendelse.

const div = document.querySelector('div');
div.addEventListener('click', () => {
  console.log("You've clicked a div element")
})

const span = document.querySelector('span');
span.addEventListener('click', () => {
  console.log("You've clicked a span element")
})

const button = document.querySelector('button');
button.addEventListener('click', () => {
  console.log("You've clicked a button")
})

Åpne nå HTML-filen i en nettleser. Inspiser siden, og klikk deretter på knappen på siden. Hva legger du merke til? Resultatet av å klikke på knappen vises nedenfor:

Ved å klikke på knappen utløses hendelseslytteren som lytter etter en klikkhendelse på knappen. Imidlertid utløses også hendelseslyttere på span- og div-elementene. Hvorfor er det slik, spør du kanskje.

Ved å klikke på knappen utløses hendelseslytteren som er knyttet til knappen, som skriver ut til konsollen. Men siden knappen er nestet inne i et span-element, betyr å klikke på knappen teknisk at vi også klikker på span-elementet, og derfor utløses hendelseslytteren.

  Hvordan skjule feilverdier og indikatorer i Microsoft Excel

Siden span-elementet også er nestet inne i div-elementet, betyr å klikke på span-elementet også at div-elementet også klikkes, og som et resultat utløses også hendelseslytteren. Dette er en begivenhet som bobler.

Event Bubbling

Hendelsesbobling er prosessen der en hendelse utløst i et nestet sett med HTML-elementer forplantes eller bobler opp fra det innerste elementet der det ble utløst og reiser opp DOM-treet til rotelementet, og trigger alle hendelseslyttere som lytter etter den hendelsen.

Hendelseslyttere utløses i en bestemt rekkefølge som samsvarer med hvordan hendelsen bobler eller forplanter seg oppover DOM-treet. Tenk på DOM-treet vist nedenfor, som representerer strukturen til HTML-en som brukes i denne artikkelen.

En klikkhendelse som bobler opp i DOM-treet

DOM-treet viser en knapp, nestet i et span, som er nestet inne i en div, som er nestet inne i kroppen og kroppen er nestet inne i HTML-elementet. Siden elementene har blitt nestet inne i hverandre når du klikker på knappen, vil klikkhendelsen utløse hendelseslytteren som er knyttet til knappen.

Men siden elementene er nestet, vil hendelsen flytte oppover DOM-treet (boble opp) til span-elementet, deretter div, deretter brødteksten og til slutt HTML-elementet, og trigge alle hendelseslyttere som lytter etter en klikkhendelse i den rekkefølge.

Dette er grunnen til at hendelseslytteren som er knyttet til span- og div-elementene, kjøres. Hvis vi hadde hendelseslyttere som lyttet etter et klikk på brødteksten og HTML-elementet, ville de også blitt utløst.

DOM-noden der en hendelse inntreffer kalles et mål. I vårt tilfelle, siden klikket skjer på knappen, er knappeelementet hendelsesmålet.

Slik stopper du hendelsesbobler

For å stoppe en hendelse fra å boble opp DOM, bruker vi en metode kalt stopPropagation() som er tilgjengelig på hendelsesobjektet. Tenk på kodeeksemplet nedenfor, som vi brukte til å legge til en hendelseslytter til knappeelementet.

const button = document.querySelector('button');
button.addEventListener('click', () => {
  console.log("You've clicked a button");
})

Koden fører til at en hendelse bobler opp i DOM-treet når en bruker klikker på knappen. For å forhindre bobling av hendelser kaller vi stopPropagation()-metoden som vist nedenfor:

const button = document.querySelector('button');
button.addEventListener('click', (e) => {
  console.log("You've clicked a button");
  e.stopPropagation();
})

En hendelsesbehandler er funksjonen som utføres når en knapp klikkes. En hendelseslytter sender automatisk et hendelsesobjekt til en hendelsesbehandler. I vårt tilfelle er dette hendelsesobjektet representert av variabelnavnet e, som sendes som en parameter i hendelsesbehandleren.

Dette hendelsesobjektet, e, inneholder informasjon om en hendelse og gir oss også tilgang til en rekke egenskaper og metoder knyttet til hendelser. En slik metode er stopPropagation(), som brukes for å forhindre bobling av hendelser. Å kalle stopPropagation() i knappens hendelseslytter forhindrer en hendelse fra å boble opp DOM-treet fra knappelementet.

  18 typer nettkriminalitet bedrifter bør være klar over

Resultatet av å klikke på knappen etter å ha lagt til stopPropagation()-metoden vises nedenfor:

Vi bruker stopPropagation() for å forhindre at en hendelse bobler opp fra elementet vi bruker den på. For eksempel, hvis vi ønsket at klikkhendelsen skulle boble opp fra knappelementet opp til span-elementet og ikke boble lenger opp i DOM-treet, ville vi brukt stopPropagation() på spans hendelseslytter.

Opptak av hendelser

Begivenhetsfangst er det motsatte av hendelsesbobler. Ved hendelsesfangst sildrer en hendelse ned fra det ytterste elementet til målelementet som illustrert nedenfor:

Klikkhendelse sildre ned til målelementet på grunn av hendelsesfangst

For eksempel, i vårt tilfelle, når du klikker på knappeelementet, i hendelsesfangst, vil hendelseslyttere på div-elementet være de første som utløses. Lytterne på span-elementet følger etter og til slutt vil lytterne på målelementet trigges.

Hendelsesbobling er imidlertid standardmåten som hendelser spres på i Document Object Model (DOM). For å endre standardoppførselen fra hendelsesbobling til hendelsesfangst, sender vi et tredje argument til hendelseslyttere våre for å sette hendelsesfangst til sann. Hvis du ikke sender inn et tredje argument til hendelseslyttere, er hendelsesfangst satt til usann.

Tenk på arrangementslytteren nedenfor:

div.addEventListener('click', () => {
  console.log("You've clicked a div element")
})

Siden det ikke har noe tredje argument, er fangst satt til usann. For å sette fangst til sann, sender vi inn et tredje argument, den boolske verdien sann, som setter fangst til sann.

div.addEventListener('click', () => {
  console.log("You've clicked a div element")
}, true)

Alternativt kan du sende inn et objekt som setter fangst til sant, som vist nedenfor:

div.addEventListener('click', () => {
  console.log("You've clicked a div element")
}, {capture: true})

For å teste ut hendelsesfangst, i JavaScript-filen din, legg til et tredje argument til alle hendelseslyttere som vist:

const div = document.querySelector('div');
div.addEventListener('click', () => {
  console.log("You've clicked a div element")
}, true)

const span = document.querySelector('span');
span.addEventListener('click', (e) => {
  console.log("You've clicked a span element")
}, true)

const button = document.querySelector('button');
button.addEventListener('click', () => {
  console.log("You've clicked a button");
}, true)

Åpne nå nettleseren din og klikk på knappen. Du bør få en slik utgang:

Legg merke til at i motsetning til hendelsesbobling, hvor utgangen fra knappen ble skrevet ut først, ved hendelsesfangst, er den første utgangen fra det ytterste elementet, div.

Hendelsesbobling og hendelsesregistrering er de viktigste måtene hendelser forplantes på i DOM. Imidlertid er hendelsesbobling det som ofte brukes til å spre hendelser.

Arrangementsdelegasjon

Hendelsesdelegering er et designmønster der en enkelt hendelseslytter er knyttet til et felles overordnet element, for eksempel et

    -element, i stedet for å ha hendelseslyttere på hvert av underelementene. Hendelser på underordnede elementer bobler deretter opp til det overordnede elementet, hvor de håndteres av hendelsesbehandleren på det overordnede elementet.

    Derfor, i et tilfelle der vi har et overordnet element med underordnede elementer inni det, legger vi bare til en hendelseslytter til det overordnede elementet. Denne hendelsesbehandleren vil håndtere alle hendelsene i underelementene.

    Du lurer kanskje på hvordan det overordnede elementet vil vite hvilket underordnet element som ble klikket på. Som nevnt før, sender en hendelseslytter et hendelsesobjekt til en hendelsesbehandler. Dette hendelsesobjektet har metoder og egenskaper som tilbyr informasjon om en bestemt hendelse. En av egenskapene i hendelsesobjektet er målegenskapen. Målegenskapen peker til det spesifikke HTML-elementet der en hendelse skjedde.

    For eksempel, hvis vi har en uordnet liste med listeelementer og vi knytter en hendelseslytter til

      -elementet når en hendelse inntreffer på et listeelement, vil målegenskapen i hendelsesobjektet peke til det spesifikke listeelementet hvor hendelsen skjedde.

      For å se hendelsesdelegering i aksjon, legg til følgende HTML-kode i den eksisterende HTML-filen:

      <ul>
          <li>Toyota</li>
          <li>Subaru</li>
          <li>Honda</li>
          <li>Hyundai</li>
          <li>Chevrolet</li>
          <li>Kia</li>
        </ul>

      Legg til følgende JavaScript-kode for å bruke hendelsesdelegering for å bruke en enkelt hendelseslytter på et overordnet element for å lytte etter hendelser i underordnede elementer:

      const ul = document.querySelector('ul');
      ul.addEventListener('click', (e) => {
        // target element
        targetElement = e.target
        // log out the content of the target element
        console.log(targetElement.textContent)
      })

      Åpne nå nettleseren og klikk på et hvilket som helst element i listen. Innholdet i elementet skal skrives ut på konsollen som vist nedenfor:

      Ved å bruke en enkelt hendelseslytter kan vi håndtere hendelser i alle underelementene. Å ha så mange hendelseslyttere på en side påvirker ytelsen, bruker mer minne, og fører til sakte lasting og gjengivelse av sider.

      Eventdelegering lar oss unngå alt dette ved å minimere antallet hendelseslyttere vi trenger å bruke på en side. Begivenhetsdelegering er avhengig av begivenhetsbobler. Derfor kan vi si at hendelsesbobler kan hjelpe til med å optimalisere ytelsen til nettsider.

      Tips for effektiv hendelseshåndtering

      Som utvikler, når du arbeider med hendelser i dokumentobjektmodellen, bør du vurdere å bruke hendelsesdelegering i stedet for å ha mange hendelseslyttere på elementer på siden din.

      Når du bruker hendelsesdelegering, husk å knytte en hendelseslytter til nærmeste felles stamfar til de underordnede elementene som trenger hendelseshåndtering. Dette hjelper til med å optimalisere hendelsesbobling og minimerer også banen en hendelse må reise før den håndteres.

      Når du håndterer hendelser, bruk hendelsesobjektet som leveres av hendelseslytteren til din fordel. Hendelsesobjektet inneholder egenskaper som mål, som kommer godt med ved håndtering av hendelser.

      For å ha mer effektive nettsteder, unngå overdreven DOM-manipulasjon. Å ha hendelser som utløser hyppige DOM-manipulasjoner kan påvirke ytelsen til nettstedet ditt negativt.

      Til slutt, i tilfelle av nestede elementer, vær veldig forsiktig når du knytter nestede hendelseslyttere til elementene. Dette kan ikke bare påvirke ytelsen, men vil gjøre hendelseshåndtering veldig kompleks, og koden din vil være vanskelig å vedlikeholde.

      Konklusjon

      Arrangementer er et kraftig verktøy i JavaScript. Hendelsesbobling, hendelsesregistrering og hendelsesdelegering er viktige verktøy for å håndtere hendelser i JavaScript. Som nettutvikler kan du bruke artikkelen til å gjøre deg kjent med konsepter slik at du kan bygge mer interaktive, dynamiske og effektive nettsteder og applikasjoner.