Uvod u pop-up događaje. Napredni rad s objektom događaja u JavaScriptu Otkazivanje bubblinga događaja js

U ovoj lekciji ćemo se upoznati s konceptom bubblinga događaja, a također ćemo pogledati kako se ono može prekinuti. Osim toga, saznat ćemo kroz koje još faze (faze) događaj prolazi prije nego što se počne pojavljivati.

Oblačić događaja

Ako se dogodi događaj za neki element, on počinje “iskakati”, tj. javlja se kod roditelja, zatim kod bake i djeda itd.

Iz toga slijedi da se događaj generiran nekim elementom može presresti korištenjem rukovatelja na roditelju, baki i djedu itd.

Demonstrirat ćemo nastanak događaja (mjehurića) koristeći sljedeći primjer:

Naslov

Neki vrlo važan tekst

Poglavlje

Neki tekst

Ostatak teksta

Napišimo malu skriptu kojom ćemo dodati rukovatelj događajima "klik" za sve elemente stranice, kao i za objekte dokumenta i prozora.

document.addEventListener("DOMContentLoaded", function() ( var allElements = document.getElementsByTagName("*"); for (var i=0; i< allElements.length; i++) { allElements[i].addEventListener("click",function() {console.log(this.tagName);},false); }; document.addEventListener("click",function() {console.log(this);},false); window.addEventListener("click",function() {console.log(this);},false); });

Kreirajmo HTML stranicu i u nju umetnimo gornji HTML kod. Skripta napisana u JavaScript, umetnite prije završne oznake tijela. Nakon toga otvorite novostvorenu stranicu u web pregledniku, pritisnite tipku F12 i idite na konzolu. Kliknimo sada lijevom tipkom miša na područje koje pripada snažnom elementu i pogledajmo kako se događaj pojavljuje.

Kako prekinuti bubbling događaja

Dizanje događaja (mjehurića) može se prekinuti. U tom slučaju, ovaj se događaj neće pokrenuti za više (roditeljske) elemente. Metoda koja je dizajnirana za zaustavljanje širenja događaja (mjehurića) zove se stopPropagation().

Na primjer, promijenimo naš gornji primjer tako da se događaj ne pojavljuje iznad tijela: document.addEventListener("DOMContentLoaded", function() ( var allElements = document.getElementsByTagName("*"); for (var i=0 i

Bez sumnje, oblaganje je vrlo zgodno i arhitektonski transparentno. Nemojte ga zaustavljati osim ako nije apsolutno neophodno.

Dohvaćanje elementa koji je pozvao rukovatelja

Da biste dobili DOM element (objekt) koji je pozvao rukovatelj događajima, morate koristiti ključ riječ ovo. S obzirom ključna riječ(ovo) dostupno je samo u rukovatelju ako se pretplatite na događaj koristeći JavaScript.

Na primjer, prikažimo u konzoli ID elementa koji je pozvao rukovatelja događajima:

Var myP = document.getElementById("myP"); myP.addEventListener("click",function())( //dobijte DOM element koji je pozvao rukovatelj događajima - ovo //dobijte njegov ID i ispišite ga na konzolu console.log(this.id); ));

Također možete koristiti svojstvo currentTarget (event.currentTarget) da dobijete trenutni element.

Faze (faze) događaja

Prije nego se događaj počne pojavljivati ​​(faza uspona), prvo prolazi kroz još 2 faze:

  • Faza 1 je faza uranjanja u element koji je generirao događaj. Oni. u ovoj fazi postoji kretanje odozgo prema dolje, tj. iz objekt prozora do elementa. Ova faza se također naziva i faza presretanja.
  • Faza 2 je faza postizanja cilja, tj. element (objekt) koji je generirao događaj.

Uzimajući u obzir sve faze kroz koje jedan događaj prolazi, dobiva se sljedeća slika:

Modificirajmo gornji primjer skripte na sljedeći način:

Document.addEventListener("DOMContentLoaded", function() ( var allElements = document.getElementsByTagName("*"); for (var i=0; i

Treći parametar metoda addEventListener i removeEventListener određuje stupanj u kojem će događaj biti uhvaćen. Ako ovaj parametar postavljeno na true, događaj će biti presretnut u fazi uranjanja (presretanja) događaja. A ako je parametar false, tada će događaj biti presretnut u fazi mjehurića. Za rukovanje događajem na samom cilju, možete koristiti metodu addEventListener kao kod vrijednost lažna, i s vrijednošću true .

Pažnja: tijekom faze uranjanja (presretanja), događaje mogu presresti samo rukovatelji dodani pomoću metode addEventListener(). Rukovatelji dodani drugim metodama ( HTML atribut ili putem JavaScripta pomoću svojstva on[event]) može presresti događaje samo u fazi mjehurića.

Dohvaćanje elementa koji je generirao događaj

Da bi se dobio ciljni element, tj. element koji je generirao događaj mora koristiti ciljno svojstvo (event.target).

Razmotrite gornji primjer u kojem mijenjamo sadržaj elementa skripte u sljedeće:

Document.addEventListener("DOMContentLoaded", function() ( var elementBody = document.body; elementBody.addEventListener("click",function())( console.log(this.tagName + " - element koji je pozvao rukovatelja") ; console .log(event.currentTarget.tagName + " - element koji je pozvao rukovatelj"); console.log(event.target.tagName + " - element koji je generirao događaj"); ),false); )) ;

Demonstrirajmo naš primjer klikom lijeve tipke miša na područje koje pripada jakom elementu:

Sve je počelo korištenjem JavaScripta i klasa.

Međutim, imam problem. Htio sam upotrijebiti nešto što se zove Bubble Events, ali sam također želio minimizirati ovisnosti koje bih morao ubaciti. Nisam se htio spojiti jQuery knjižnice za "ovaj mali test", samo za korištenje skočnih događaja.

Pogledajmo pobliže što su događaji nazdravljanja, kako funkcioniraju i nekoliko načina za njihovu provedbu.

U redu, u čemu je problem? Pogledajmo jednostavan primjer:

Recimo da imamo popis gumba. Svaki put kad kliknem na jedan od njih, trebao bi postati "aktivan". Nakon ponovnog pritiska tipka bi se trebala vratiti u prvobitno stanje.

Počnimo s HTML-om:

  • Olovka
  • Olovka
  • gumica za brisanje

Mogao bih koristiti standardni JavaScript rukovatelj događajima poput ovog:

Za(var i = 0; i< buttons.length; i++) { var button = buttons[i]; button.addEventListener("click", function() { if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active"); }); }
Izgleda dobro... Ali neće uspjeti. Po barem, ne onako kako to očekujemo.

Zatvaranja pobjeđuju Za one koji poznaju iole funkcionalan JavaScript, problem je očit.

Za ostalo ću ukratko objasniti - funkcija rukovatelja je zaključana na varijablu gumba. Međutim, ovo je jedna varijabla i prepisuje se preko svake iteracije.

U prvoj iteraciji, varijabla se odnosi na prvi gumb. U sljedećem - do drugog, i tako dalje. Ali, kada korisnik klikne na gumb, petlja je već završila i varijabla gumba se odnosi na zadnji gumb, koji uvijek poziva rukovatelja događajima za njega. Poremećaj.

Ono što nam treba je zaseban kontekst za svaku funkciju:

Var buttons = document.querySelectorAll(".gumb alatne trake"); var createToolbarButtonHandler = function(button) ( return function() ( if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active"); ); ); for(var i = 0; i< buttons.length; i++) { buttons[i].addEventListener("click", createToolBarButtonHandler(buttons[i])); }
Puno bolje! I što je najvažnije, radi ispravno. Stvorili smo funkciju createToolbarButtonHandle koja vraća rukovatelj događajima. Zatim za svaki gumb pričvrstimo vlastiti držač.

Pa u čemu je problem? Izgleda dobro i radi. Unatoč tome, još uvijek možemo poboljšati naš kôd.

Prvo, stvaramo previše rukovatelja. Za svaki gumb unutar .toolbara stvaramo funkciju i povezujemo je kao rukovatelja događajima. Za tri tipke korištenje memorije je zanemarivo.

Ali ako imamo ovako nešto:

  • fuj
  • Bar
  • // ...još 997 elemenata...
  • baz

tada računalo, naravno, neće eksplodirati od prelijevanja. Međutim, naša upotreba memorije daleko je od idealne. Odvajamo ga ogromne količine, iako možemo i bez njega. Ponovno napišimo naš kod kako bismo mogli koristiti istu funkciju više puta.

Umjesto pozivanja na varijablu gumba da pratimo koji smo gumb kliknuli, možemo koristiti objekt događaja koji se prosljeđuje kao prvi argument svakom rukovatelju događajima.

Objekt Event sadrži neke podatke o događaju. U našem slučaju, zanima nas polje currentTarget. Iz njega ćemo dobiti poveznicu na element na koji smo kliknuli:

Var toolbarButtonHandler = function(e) ( var button = e.currentTarget; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active" ); ); for(var i = 0; i< buttons.length; i++) { button.addEventListener("click", toolbarButtonHandler); }
Sjajno! Ne samo da smo sve pojednostavili na jednu funkciju koja se koristi više puta, već smo također učinili naš kod čitljivijim uklanjanjem nepotrebne funkcije generatora.

Međutim, još uvijek možemo bolje.

Recimo da smo dodali neke gumbe na list nakon što se naš kod izvršio. Zatim bismo također morali dodati rukovatelje događajima za svaki od njih. I morali bismo pohraniti vezu na ovaj rukovatelj i veze s drugih mjesta. Ne izgleda previše primamljivo.

Možda postoji neki drugi pristup?

Počnimo s razumijevanjem kako događaji funkcioniraju i kako se kreću duž našeg DOM-a.

Kako većina njih radi? Kada korisnik klikne na element, generira se događaj koji obavještava aplikaciju o tome. Putovanje svakog događaja odvija se u tri faze:
  • Faza presretanja
  • Događaj se događa na ciljnom elementu
  • Faza uspona
  • Napomena: ne prolaze svi događaji kroz fazu presretanja ili mjehurića; neki se kreiraju odmah na elementu. Međutim, ovo je prije iznimka od pravila.

    Događaj se stvara izvan dokumenta, a zatim se sekvencijalno premješta kroz DOM hijerarhiju do ciljnog elementa. Nakon što dosegne cilj, događaj se na isti način dohvaća iz DOM elementa.

    Evo našeg HTML predloška:

    • Gumb A
    • Gumb B
    • Gumb C

    Kada korisnik klikne gumb A, događaj putuje ovako:

    Početak
    | #dokument
    | Faza presretanja
    | HTML
    | TIJELO
    | UL
    | LI#li_1
    | Gumb A< - Событие возникает для целевого элемента
    | Faza uspona
    | LI#li_1
    | UL
    | TIJELO
    | HTML
    v #dokument

    Primijetite da možemo pratiti put kojim događaj dolazi do ciljnog elementa. U našem slučaju, za svaki pritisnut gumb, možemo biti sigurni da će se događaj vratiti u mjehurić, prolazeći kroz svog roditelja - element ul. Možemo to iskoristiti i implementirati skočne događaje.

    Bubble Events Bubble događaji su oni događaji koji su pridruženi nadređenom elementu, ali se izvršavaju samo ako zadovoljavaju neki uvjet.

    Uzmimo našu alatnu traku kao konkretan primjer:

    Ul class="toolbar">

  • Olovka
  • Olovka
  • gumica za brisanje

  • Sada kada znamo da će svaki klik na gumb iskočiti kroz element ul.toolbar, pridružimo mu naš rukovatelj događajima. Srećom, već ga imamo:

    Var toolbar = document.querySelector(".toolbar"); toolbar.addEventListener("click", function(e) ( var button = e.target; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList. ukloni("aktivno"); ));
    Sada imamo puno čišći kod, a čak smo se riješili i petlji! Imajte na umu da smo zamijenili e.currentTarget s e.target. Razlog leži u činjenici da događaje obrađujemo na drugoj razini.

    e.target je stvarna meta događaja, gdje se probija kroz DOM, i odakle će se zatim pojaviti.
    e.currentTarget - trenutni element koji obrađuje događaj. U našem slučaju to je ul.toolbar.

    Poboljšani Bubble Events ovaj trenutak Obrađujemo svaki klik na svaki element koji se pojavi putem ul.toolbar, ali naš uvjet provjere valjanosti je previše jednostavan. Što bi se dogodilo da imamo složeniji DOM koji uključuje ikone i elemente koji nisu dizajnirani da se na njih klikne?

    • Olovka
    • Olovka
    • gumica za brisanje

    Ups! Sada kada kliknemo li.separator ili ikonu, dodajemo mu klasu .active. Ovo u najmanju ruku nije dobro. Trebamo način filtriranja događaja kako bismo reagirali na element koji nam je potreban.

    Kreirajmo malu pomoćnu funkciju za ovo:

    Var delegat = function(criteria, listener) ( return function(e) ( var el = e.target; do ( if (!criteria(el)) continue; e.delegateTarget = el; listener.apply(this, arguments); return; ) while((el = el.parentNode)); ); );
    Naš pomoćnik radi dvije stvari. Prvo će iterirati po svakom elementu i njegovim roditeljima i provjeriti zadovoljavaju li uvjet proslijeđen u parametru kriterija. Ako element zadovoljava, pomoćnik dodaje polje objektu događaja pod nazivom delegateTarget, koje pohranjuje element koji zadovoljava naše uvjete. I onda poziva voditelja. Prema tome, ako niti jedan element ne zadovoljava uvjet, neće biti pozvan nijedan rukovatelj.

    Možemo ga koristiti ovako:

    Var toolbar = document.querySelector(".toolbar"); var buttonsFilter = function(elem) ( return elem.classList && elem.classList.contains("btn"); ); var buttonHandler = function(e) ( var button = e.delegateTarget; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active" ); ); toolbar.addEventListener("klik", delegat(buttonsFilter, buttonHandler));
    Upravo ono što je liječnik naredio: jedan rukovatelj događajima priključen na jedan element koji obavlja sav posao. Ali to čini samo za elemente koji su nam potrebni. I savršeno reagira na dodavanje i uklanjanje objekata iz DOM-a.

    Sažetak Ukratko smo pregledali osnove implementacije delegiranja (upravljanje skočnim prozorima) događaja na čisti JavaScript. Ovo je dobro jer ne trebamo generirati i priložiti hrpu rukovatelja za svaki element.

    Da želim od ovoga napraviti biblioteku ili koristiti kod u razvoju, dodao bih nekoliko stvari:

    Pomoćna funkcija za provjeru ispunjava li objekt kriterije u jedinstvenijem i funkcionalnijem obliku. Kao:

    Var kriteriji = ( isElement: function(e) ( return e instanceof HTMLElement; ), hasClass: function(cls) ( return function(e) ( return критерии.isElement(e) && e.classList.contains(cls); ) ) //Više kriterija);
    Djelomično korištenje pomoćnika također bi bilo korisno:

    Var partialDelgate = function(criteria) ( return function(handler) ( return delgate(criteria, handler); ) );
    Izvorni članak: Razumijevanje delegiranih JavaScript događaja
    (Od prevoditelja: moj prvi, sudite strogo.)

    Sretno kodiranje!

    Događaji su radnje ili pojave koje se događaju u sustavu koji programirate, o kojima vam sustav govori kako biste na njih mogli odgovoriti na neki način ako želite. Na primjer, ako korisnik klikne gumb na web stranici, možda biste željeli odgovoriti na tu radnju prikazivanjem okvira s informacijama. U ovom članku raspravljamo o nekim važnim konceptima vezanim uz događaje i gledamo kako oni funkcioniraju u preglednicima. Ovo neće biti iscrpna studija; samo što trebaš znati u ovoj fazi.

    Preduvjeti: Cilj:
    Osnovna informatička pismenost, osnovno razumijevanje HTML i CSS, JavaScript prvi koraci.
    Razumjeti temeljnu teoriju događaja, kako rade u preglednicima i kako se događaji mogu razlikovati u različitim programskim okruženjima.
    Niz sretnih događaja

    Kao što je gore spomenuto, događaji su radnje ili pojave koje se događaju u sustavu koji programirate - sustav proizvodi (ili "ispaljuje") signal neke vrste kada se događaj dogodi, a također pruža mehanizam pomoću kojeg se neka vrsta radnje može automatski uzeti (to jest, neki kod se izvodi) kada se događaj dogodi. Na primjer, u zračnoj luci kada je uzletno-sletna staza slobodna za polijetanje aviona, signal se šalje pilotu i kao rezultat toga, oni počinju upravljati avionom.

    U slučaju weba, događaji se pokreću unutar prozora preglednika i teže biti pridruženi određenoj stavci koja se nalazi u njemu - to može biti jedan element, skup elemenata, HTML dokument učitan u trenutnoj kartici ili cijeli prozor preglednika. Postoji mnogo različitih vrsta događaja koji se mogu dogoditi, na primjer:

    • Korisnik klikne mišem preko određenog elementa ili pređe pokazivačem iznad određenog elementa.
    • Korisnik pritiska tipku na tipkovnici.
    • Korisnik mijenja veličinu ili zatvara prozor preglednika.
    • Šalje se obrazac.
    • Videozapis koji se reproducira, pauzira ili završava.
    • Došlo je do pogreške.

    Iz ovoga (i iz pogleda na referencu MDN događaja) možete zaključiti da postoji mnogo događaja na koje se može odgovoriti.

    Svaki dostupni događaj ima rukovatelja događajem, koji je blok koda (obično JavaScript funkcija koju vi kao programer kreirate) koji će se pokrenuti kada se događaj pokrene. Kada je takav blok koda definiran da se pokreće kao odgovor na pokretanje događaja, kažemo da registriramo rukovatelja događajem. Imajte na umu da se rukovatelji događajima ponekad nazivaju slušateljima događaja - oni su prilično međusobno zamjenjivi za naše potrebe, iako strogo govoreći, rade zajedno. Slušatelj osluškuje događaj koji se događa, a rukovatelj je kod koji se pokreće kao odgovor na to što se događa.

    Napomena: Web događaji nisu dio osnovnog jezika JavaScript - definirani su kao dio API-ja ugrađenih u preglednik.

    Jednostavan primjer

    Pogledajmo jednostavan primjer da objasnimo što ovdje mislimo. Već ste vidjeli događaje i rukovatelje događajima korištene u mnogim primjerima u ovom tečaju, ali rezimiramo samo da učvrstimo naše znanje. U sljedećem primjeru imamo single , koji kada se pritisne, mijenja pozadinu u nasumičnu boju:

    Promjena boje

    Gumb (margina: 10px);

    JavaScript izgleda ovako:

    Const btn = document.querySelector("gumb"); funkcija random(number) ( return Math.floor(Math.random() * (number+1)); ) btn.onclick = function() ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol; )

    U ovom kodu pohranjujemo referencu na gumb unutar konstante pod nazivom btn, koristeći funkciju Document.querySelector(). Također definiramo funkciju koja vraća slučajni broj. Treći dio koda je rukovatelj događajima. Konstanta btn pokazuje na element, a ova vrsta objekta ima niz događaja koji se mogu pokrenuti na njemu, i stoga su dostupni rukovatelji događajima. Osluškujemo pokretanje događaja klika postavljajući svojstvo rukovatelja događajem onclick da bude jednako anonimnoj funkciji koja sadrži kod koji generira slučajnu RGB boju i postavlja boju pozadine jednaku njoj.

    Ovaj se kod pokreće kad god se događaj klika aktivira na elementu, odnosno kad god korisnik klikne na njega.

    Primjer izlaza je sljedeći:

    Nisu to samo web stranice

    Još jedna stvar koju vrijedi spomenuti u ovom trenutku je da događaji nisu jedinstveni za JavaScript - većina programskih jezika ima neku vrstu modela događaja, a način na koji model funkcionira često se razlikuje od načina JavaScripta. Zapravo, model događaja u JavaScriptu za web stranice razlikuje se od modela događaja za JavaScript jer se koristi u drugim okruženjima.

    Inline rukovatelji događajima - nemojte ih koristiti

    U svom kodu također možete vidjeti obrazac poput ovog:

    Pritisnite me, funkcija bgChange() ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol; )

    Najraniji način registriranja rukovatelja događajima pronađen na webu uključivao je HTML atribute rukovatelja događajima (ili ugrađene rukovatelje događajima) poput onog prikazanog gore - vrijednost atributa doslovno je JavaScript kod koji želite pokrenuti kada se događaj dogodi. Gornji primjer poziva funkciju definiranu unutar elementa na istoj stranici, ali također možete umetnuti JavaScript izravno unutar atributa, na primjer:

    pritisni me

    Možete pronaći ekvivalente HTML atributa za mnoga svojstva rukovatelja događajima; međutim, ne biste ih trebali koristiti - smatraju se lošom praksom.Moglo bi se činiti lakim korištenje atributa rukovatelja događajima ako samo radite nešto jako brzo, ali oni vrlo brzo postanu neupravljivi i neučinkoviti.

    Za početak, nije dobra ideja miješati svoj HTML i JavaScript, jer postaje teško analizirati - bolje je držati svoj JavaScript na jednom mjestu; ako je u zasebnoj datoteci, možete ga primijeniti na više HTML dokumenata.

    Čak ni u jednoj datoteci, ugrađeni rukovatelji događajima nisu dobra ideja. Jedan gumb je OK, ali što ako imate 100 gumba? Morali biste dodati 100 atributa datoteci; to bi se vrlo brzo pretvorilo u održavanje. S JavaScriptom biste lako mogli kao noćna mora dodati funkciju rukovatelja događajima svim gumbima na stranici bez obzira koliko ih bilo, koristeći nešto poput ovaj:

    Const buttons = document.querySelectorAll("button"); za (neka je i = 0; i< buttons.length; i++) { buttons[i].onclick = bgChange; } buttons.forEach(function(button) { button.onclick = bgChange; });

    Napomena: Odvajanje vaše programske logike od vašeg sadržaja također čini vašu web stranicu prijateljskom prema tražilicama.

    addEventListener() i removeEventListener()

    Najnovija vrsta mehanizma događaja definirana je u Specifikaciji događaja razine 2 Document Object Model (DOM), koja preglednicima pruža novu funkciju - addEventListener() . Ovo funkcionira na sličan način kao svojstva rukovatelja događajima, ali je sintaksa očito drugačija. Mogli bismo prepisati naš primjer nasumične boje da izgleda ovako:

    Const btn = document.querySelector("gumb"); funkcija bgChange() ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol; ) btn.addEventListener("klik", bgPromijeni);

    Unutar funkcije addEventListener() specificiramo dva parametra - naziv događaja za koji želimo registrirati ovaj rukovatelj i kod koji sadrži funkciju rukovatelja koju želimo pokrenuti kao odgovor na njega. Imajte na umu da je savršeno prikladno staviti sav kod unutar funkcije addEventListener(), u anonimnu funkciju, poput ove:

    Btn.addEventListener("click", function() ( var rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body .style.backgroundColor = rndCol; ));

    Ovaj mehanizam ima neke prednosti u odnosu na starije mehanizme o kojima smo ranije govorili. Za početak, postoji odgovarajuća funkcija, removeEventListener() , koja uklanja prethodno dodanog slušatelja. Na primjer, ovo bi uklonilo skup slušatelja u prvom bloku koda u ovom odjeljku:

    Btn.removeEventListener("klik", bgPromijeni);

    Ovo nije značajno za jednostavne, male programe, ali za veće, složenije programe može poboljšati učinkovitost čišćenja starih neiskorištenih rukovatelja događajima. Plus, na primjer, ovo vam omogućuje da isti gumb izvodi različite radnje u različitim okolnostima - sve što trebate učiniti je dodati ili ukloniti rukovatelje događajima prema potrebi.

    Drugo, također možete registrirati više rukovatelja za istog slušatelja. Sljedeća dva rukovatelja ne bi se oba primijenila:

    MojElement.onclick = funkcijaA; mojElement.onclick = funkcijaB;

    Drugi redak prepisuje vrijednost onclick postavljenu u prvom redu. Ovo bi, međutim, funkcioniralo:

    MyElement.addEventListener("klik", funkcijaA); myElement.addEventListener("klik", funkcijaB);

    Obje funkcije sada bi se pokrenule kada se element klikne.

    Osim toga, postoji niz drugih moćnih značajki i opcija dostupnih uz ovaj mehanizam događaja. Oni su malo izvan opsega ovog članka, ali ako želite pročitati o njima, pogledajte referentne stranice addEventListener() i removeEventListener().

    Koji mehanizam trebam koristiti?

    Od tri mehanizma, definitivno ne biste trebali koristiti atribute rukovatelja HTML događajima - oni su zastarjeli i loša praksa, kao što je gore spomenuto.

    Druga dva su relativno zamjenjiva, barem za jednostavne upotrebe:

    • Svojstva rukovatelja događajima imaju manje snage i mogućnosti, ali bolju kompatibilnost s više preglednika (podržana su još od Internet Explorer 8). Vjerojatno biste trebali početi s njima dok učite.
    • Događaji DOM razine 2 (addEventListener() itd.) su snažniji, ali također mogu postati složeniji i manje su podržani (podržani još od Internet Explorera 9). Također biste trebali eksperimentirati s njima i nastojati ih koristiti gdje god je to moguće.

    Glavne prednosti trećeg mehanizma su da možete ukloniti kod rukovatelja događajima ako je potrebno, koristeći removeEventListener() i možete dodati više slušatelja iste vrste elementima ako je potrebno. Na primjer, možete pozvati addEventListener("click", function() ( ... )) na elementu više puta, s različitim funkcijama navedenim u drugom argumentu. Ovo je nemoguće sa svojstvima rukovatelja događajima jer će svi sljedeći pokušaji postavljanja svojstva prebrisati prethodne, npr.:

    Element.onclick = funkcija1; element.onclick = funkcija2; itd.

    Napomena: Ako se od vas traži da u svom radu podržavate preglednike starije od Internet Explorera 8, mogli biste naići na poteškoće jer takvi stari preglednici koriste različite modele događaja od novijih preglednika. Ali nemojte se bojati, većina JavaScript biblioteka (na primjer jQuery) ima ugrađene funkcije koje apstrahiraju razlike između preglednika. Ne brinite o tome previše u ovoj fazi vašeg učenja.

    Ostali koncepti događaja

    U ovom odjeljku ukratko pokrivamo neke napredne koncepte koji su relevantni za događaje. U ovom trenutku nije važno u potpunosti razumjeti ove koncepte, ali oni mogu poslužiti za objašnjenje nekih obrazaca koda na koje ćete vjerojatno naići s vremena na vrijeme.

    Objekti događaja

    Ponekad unutar funkcije rukovatelja događajem možete vidjeti parametar naveden imenom kao što je događaj, evt ili jednostavno e. To se naziva objekt događaja i automatski se prosljeđuje rukovateljima događajima kako bi pružili dodatne značajke i informacije. Na primjer, ponovno malo prepišimo naš primjer nasumične boje:

    Funkcija bgChange(e) ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; e.target.style.backgroundColor = rndCol ; console.log(e); ) btn.addEventListener("klik", bgPromijeni);

    Ovdje možete vidjeti da uključujemo objekt događaja, e , u funkciju, au funkciji postavljamo stil boje pozadine na e.target - što je sam gumb. Ciljno svojstvo objekta događaja uvijek je referenca na element na kojem se događaj upravo dogodio. Dakle, u ovom primjeru postavljamo nasumičnu boju pozadine na gumbu, a ne na stranici.

    Napomena: Možete koristiti bilo koji naziv koji želite za objekt događaja - samo trebate odabrati naziv koji zatim možete koristiti za referencu unutar funkcije rukovatelja događajima. e/evt/event programeri najčešće koriste jer su kratki i lako se pamte. Uvijek je dobro biti dosljedan - sa samim sobom, a ako je moguće i s drugima.

    e.target je nevjerojatno koristan kada želite postaviti isti rukovatelj događajima na više elemenata i učiniti nešto sa svima njima kada se na njima dogodi događaj. Možete, na primjer, imati skup od 16 pločica koje nestaju kada se na njih klikne. Korisno je uvijek moći samo postaviti da stvar nestane kao e.target, umjesto da je morate odabrati na neki teži način. U sljedećem primjeru (pogledajte korisni-eventtarget.html za potpuni izvorni kod; također ga pogledajte uživo ovdje), stvaramo 16 elemenata koristeći JavaScript. Zatim ih sve odabiremo pomoću document.querySelectorAll() , zatim prolazimo kroz svaku od njih, dodajući onclick rukovatelj svakoj koja čini tako da se na svaku primjenjuje nasumična boja kada se klikne:

    Const divs = document.querySelectorAll("div"); za (neka je i = 0; i< divs.length; i++) { divs[i].onclick = function(e) { e.target.style.backgroundColor = bgChange(); } }

    Ispis je sljedeći (probajte kliknuti na njega - zabavite se):

    Skriveni primjer Primjer cilja cilja korisnog događaja div ( visina: 100 piksela; širina: 25%; float: lijevo; ) za (neka je i = 1; i
  • Olovka
  • Olovka
  • gumica za brisanje

  • Sada kada znamo da će svaki klik na gumb iskočiti kroz element ul.toolbar, pridružimo mu naš rukovatelj događajima. Srećom, već ga imamo:

    Var toolbar = document.querySelector(".toolbar"); toolbar.addEventListener("click", function(e) ( var button = e.target; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList. ukloni("aktivno"); ));
    Sada imamo puno čišći kod, a čak smo se riješili i petlji! Imajte na umu da smo zamijenili e.currentTarget s e.target. Razlog leži u činjenici da događaje obrađujemo na drugoj razini.

    e.target je stvarna meta događaja, gdje se probija kroz DOM, i odakle će se zatim pojaviti.
    e.currentTarget - trenutni element koji obrađuje događaj. U našem slučaju to je ul.toolbar.

    Poboljšani skočni događaji Trenutačno obrađujemo svaki klik na svaki element koji se pojavi putem ul.toolbar, ali naš uvjet provjere valjanosti je previše jednostavan. Što bi se dogodilo da imamo složeniji DOM koji uključuje ikone i elemente koji nisu dizajnirani da se na njih klikne?

    • Olovka
    • Olovka
    • gumica za brisanje

    Ups! Sada kada kliknemo li.separator ili ikonu, dodajemo mu klasu .active. Ovo u najmanju ruku nije dobro. Trebamo način filtriranja događaja kako bismo reagirali na element koji nam je potreban.

    Kreirajmo malu pomoćnu funkciju za ovo:

    Var delegat = function(criteria, listener) ( return function(e) ( var el = e.target; do ( if (!criteria(el)) continue; e.delegateTarget = el; listener.apply(this, arguments); return; ) while((el = el.parentNode)); ); );
    Naš pomoćnik radi dvije stvari. Prvo će iterirati po svakom elementu i njegovim roditeljima i provjeriti zadovoljavaju li uvjet proslijeđen u parametru kriterija. Ako element zadovoljava, pomoćnik dodaje polje objektu događaja pod nazivom delegateTarget, koje pohranjuje element koji zadovoljava naše uvjete. I onda poziva voditelja. Prema tome, ako niti jedan element ne zadovoljava uvjet, neće biti pozvan nijedan rukovatelj.

    Možemo ga koristiti ovako:

    Var toolbar = document.querySelector(".toolbar"); var buttonsFilter = function(elem) ( return elem.classList && elem.classList.contains("btn"); ); var buttonHandler = function(e) ( var button = e.delegateTarget; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active" ); ); toolbar.addEventListener("klik", delegat(buttonsFilter, buttonHandler));
    Upravo ono što je liječnik naredio: jedan rukovatelj događajima priključen na jedan element koji obavlja sav posao. Ali to čini samo za elemente koji su nam potrebni. I savršeno reagira na dodavanje i uklanjanje objekata iz DOM-a.

    Sažetak Ukratko smo pogledali osnove implementacije događaja delegiranja (upravljanje skočnim prozorima) u čistom JavaScriptu. Ovo je dobro jer ne trebamo generirati i priložiti hrpu rukovatelja za svaki element.

    Da želim od ovoga napraviti biblioteku ili koristiti kod u razvoju, dodao bih nekoliko stvari:

    Pomoćna funkcija za provjeru ispunjava li objekt kriterije u jedinstvenijem i funkcionalnijem obliku. Kao:

    Var kriteriji = ( isElement: function(e) ( return e instanceof HTMLElement; ), hasClass: function(cls) ( return function(e) ( return критерии.isElement(e) && e.classList.contains(cls); ) ) //Više kriterija);
    Djelomično korištenje pomoćnika također bi bilo korisno:

    Var partialDelgate = function(criteria) ( return function(handler) ( return delgate(criteria, handler); ) );
    Izvorni članak: Razumijevanje delegiranih JavaScript događaja
    (Od prevoditelja: moj prvi, sudite strogo.)

    Sretno kodiranje!

    Zdravo! U ovoj lekciji želim govoriti o tako važnom konceptu kao što je izranjanje i presretanje događaja. Bubbling je fenomen gdje ako kliknete na podređeni element, događaj se prenosi na njegovog roditelja.

    Može biti vrlo korisno pri obradi velikih ugniježđenih popisa ili tablica, tako da ne dodjeljujete rukovatelja događajem svakom elementu, možete dodijeliti jedan rukovatelj roditeljskom elementu, a događaj će se već proširiti na sve ugniježđene elemente u roditelju. Pogledajmo primjer.

    Ovaj rukovatelj aktivirat će se ako kliknete na podoznaku ili :

    Kliknite na EM, rukovatelj na DIV će raditi

    Kao što vidite, kada kliknete na ugniježđeni em element, aktivira se rukovatelj na divu. Zašto se ovo događa? Čitajte dalje i saznajte.

    Uspon

    Dakle, osnovni princip uspona:

    Kada postoji događaj bilo koje vrste, nije važno klikne li se mišem na element, događaj će se prvo pokrenuti na nadređenom elementu, a zatim će se duž lanca proširiti na sve ugniježđene elemente.

    Na primjer, pretpostavimo da postoje 3 ugniježđena elementa FORM > DIV > P, s rukovateljem događaja na svakom:

    tijelo * (margina: 10px; obrub: 1px jednobojno plavo; ) FORM DIV

    Bubbling osigurava klik na unutarnji element

    Prvo će pozvati rukovatelja klikovima (ako postoji, naravno) na stvarnom

    Taj se proces naziva uspon, jer se čini da događaji "lebde" od unutarnjeg elementa prema gore kroz svoje roditelje, baš kao što mjehurić zraka lebdi u vodi, tako da možete pronaći i definiciju mjehurića, pa, to je samo iz engleskog riječ bubbling - isplivati.

    Pristup ciljnom elementu event.target

    Kako bismo saznali na kojem elementu smo uhvatili ovaj ili onaj događaj, postoji metoda event.target. (pročitajte o objektu događaja).

    • event.target je stvarni izvorni element na kojem se događaj dogodio.
    • ovo je uvijek trenutni element do kojeg je bubbling došao, a rukovatelj je trenutno pokrenut na njemu.

    Na primjer, ako imate samo jedan form.onclick rukovatelj instaliran, tada će on "uhvatiti" sve klikove unutar forme. Štoviše, bez obzira gdje je klik unutra, on će i dalje iskočiti do elementa na kojem će rukovatelj raditi.

    pri čemu:

    • ovo (=event.currentTarget) će uvijek biti sama forma, budući da je rukovatelj pokrenut na njoj.
    • event.target sadržavat će poveznicu na određeni element unutar obrasca, onaj koji je najviše ugniježđen na koji se klik dogodio.

    U principu, to se može podudarati s event.target ako se klikne na obrazac i nema više elemenata u obrascu.

    Zaustavljanje uspona

    Tipično, mjehurić događaja ide ravno na vrh i doseže objekt korijenskog prozora.

    Ali moguće je zaustaviti uspon na nekom srednjem elementu.

    Kako biste zaustavili širenje, morate pozvati metodu event.stopPropagation().

    Pogledajmo primjer: kada se klikne gumb, rukovatelj body.onclick neće raditi:

    Klikni me

    Ako element ima nekoliko instaliranih rukovatelja za isti događaj, tada će se svi izvršiti, čak i ako mjehurići prestanu.

    Stoga će stopPropagation spriječiti daljnje širenje događaja, ali će svi rukovatelji raditi na elementu, ali ne i na sljedećem elementu.

    Za zaustavljanje obrade trenutnog elementa preglednici podržavaju metodu event.stopImmediatePropagation(). Ova metoda ne samo da će spriječiti pojavu mjehurića, već će i zaustaviti obradu događaja na trenutnom elementu.

    Ronjenje

    U standardu, osim "uspona" događaja, postoji i "zaron".

    Ronjenje je, za razliku od uspona, manje traženo, ali će i dalje biti korisno znati za to.

    Dakle, postoje 3 faze događaja:

  • Događaj dolazi odozgo prema dolje. Ova faza se naziva "faza presretanja".
  • Događaj je dosegao određeni element. Ovo je "faza cilja".
  • Nakon svega počinje nastajati događaj. Ovo je "faza uspona".
  • To je prikazano u standardu na sljedeći način:

    Dakle, kada kliknete na TD, događaj će putovati duž lanca roditelja, najprije prema dolje do elementa ("potone"), a zatim prema gore ("pops up"), koristeći odgovarajući rukovatelji usput.

    Gore sam pisao samo o usponu, jer se ostale etape ne koriste i prolaze mimo nas nezapaženo.

    Voditelji ne znaju ništa o stupnju presretanja, ali počinju raditi od uspona.

    A da biste uhvatili događaj u fazi presretanja, samo trebate upotrijebiti:

    • Argument je istinit, tada će događaj biti presretnut na putu prema dolje.
    • Argument je netočan, tada će događaj biti uhvaćen prilikom mjehurića.
    Primjeri

    U primjeru na , ,

    Procesori su isti kao i prije, ali ovaj put u immersion fazi. Da biste vidjeli presretanje na djelu, kliknite na element u njemu

    Rukovatelji će raditi odozgo prema dolje: FORM → DIV → P.

    JS kod ovdje je:

    Var elems = document.querySelectorAll("form,div,p"); // priložite rukovatelja svakom elementu u fazi presretanja za (var i = 0; i< elems.length; i++) { elems[i].addEventListener("click", highlightThis, true); }


    Nitko vas ne sprječava da dodijelite rukovatelje za obje faze, ovako:

    Var elems = document.querySelectorAll("form,div,p"); za (var i = 0; i< elems.length; i++) { elems[i].addEventListener("click", highlightThis, true); elems[i].addEventListener("click", highlightThis, false); }

    Kliknite na unutarnji element

    Da biste vidjeli redoslijed događaja:
    Trebao bi biti FORM → DIV → P → P → DIV → FORM. Imajte na umu da element

    Sudjelovat će u obje faze.

    Rezultati
    • Kada se događaj dogodi, element na kojem se događaj dogodio označava se kao event.target.
    • Događaj se prvo pomiče prema dolje iz korijena dokumenta u event.target, usput pozivajući rukovatelje, koji se dostavljaju putem addEventListener(…., true).
    • Događaj se pomiče od event.target do početka dokumenta, usput poziva rukovatelje dostavljene putem addEventListener(…., false).

    Svaki rukovatelj imat će pristup svojstvima događaja:

    • event.target je najdublji element gdje se događaj zapravo dogodio.
    • event.currentTarget (=this) – element na kojem je trenutno aktiviran self-handler (do kojeg je događaj “došao”).
    • event.eventPhase – u kojoj je fazi pokretač rukovatelja događajem (ronjenje = 1, izron = 3).

    Propagacija se može zaustaviti pozivanjem metode event.stopPropagation(), ali to se ne preporučuje jer vam događaj može trebati za najneočekivanije svrhe.