Ievads uznirstošajos notikumos. Papildu darbs ar notikumu objektu programmā JavaScript Notikumu burbuļošanas js atcelšana

Šajā nodarbībā mēs iepazīsimies ar notikumu burbuļošanas jēdzienu, kā arī aplūkosim, kā to var pārtraukt. Turklāt mēs uzzināsim, kādus citus posmus (fāzes) notikums iziet, pirms tas sāk parādīties.

Pasākumu burbulis

Ja kādam elementam notiek notikums, tas sāk “uznirst”, t.i. rodas vecākam, tad vecvecākam utt.

No tā izriet, ka kāda elementa ģenerētu notikumu var pārtvert, izmantojot apdarinātāju tā vecākajā, vecvecākā utt.

Mēs demonstrēsim notikuma (burbuļa) rašanos, izmantojot šādu piemēru:

Virsraksts

Daži ļoti svarīgi teksti

nodaļa

Kaut kāds teksts

Pārējais teksts

Uzrakstīsim nelielu skriptu, ar kuru visiem lapas elementiem, kā arī dokumenta un loga objektiem pievienosim notikumu apstrādātāju "klikšķis".

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); });

Izveidosim HTML lapu un ielīmēsim tajā iepriekš minēto HTML kodu. Ierakstīts skripts JavaScript, ievietojiet pirms aizverošā pamatteksta taga. Pēc tam atveriet jaunizveidoto lapu tīmekļa pārlūkprogrammā, nospiediet taustiņu F12 un dodieties uz konsoli. Tagad noklikšķināsim ar peles kreiso taustiņu apgabalā, kas pieder spēcīgajam elementam, un redzēsim, kā notikums parādās.

Kā pārtraukt notikumu burbuļošanu

Notikuma (burbuļa) celšanās var tikt pārtraukta. Šajā gadījumā šis notikums netiks aktivizēts augstākiem (vecākiem) elementiem. Metode, kas paredzēta, lai apturētu notikuma (burbuļa) izplatīšanos, tiek saukta par stopPropagation() .

Piemēram, mainīsim iepriekš minēto piemēru, lai notikums neburbuļotu virs pamatteksta: document.addEventListener("DOMContentLoaded", function() ( var allElements = document.getElementsByTagName("*"); for (var i=0 i

Neapšaubāmi, segums ir ļoti ērts un arhitektoniski caurspīdīgs. Nepārtrauciet to, ja vien tas nav absolūti nepieciešams.

Elementa iegūšana, kas izsauca apdarinātāju

Lai iegūtu DOM elementu (objektu), kas izsauca notikumu apstrādātāju, ir jāizmanto atslēga vārds šis. Ņemot vērā atslēgvārds(šis) ir pieejams apdarinātājā tikai tad, ja abonējat notikumu, izmantojot JavaScript.

Piemēram, parādīsim konsolē tā elementa ID, kas izsauca notikumu apstrādātāju:

Var myP = document.getElementById("mansP"); myP.addEventListener("klikšķis",funkcija())( //iegūstiet DOM elementu, kas izsauca notikumu apdarinātāju - //iegūstiet tā id un izvadiet to konsolei console.log(this.id); ));

Varat arī izmantot rekvizītu currentTarget (event.currentTarget), lai iegūtu pašreizējo elementu.

Pasākuma posmi (fāzes).

Pirms notikuma sāk parādīties (pacelšanās posms), tas vispirms iziet vēl 2 posmus:

  • 1. posms ir iegremdēšanās posms elementā, kas ģenerēja notikumu. Tie. šajā posmā notiek kustība no augšas uz leju, t.i. no loga objekts uz elementu. Šo posmu sauc arī par pārtveršanas stadiju.
  • 2. posms ir mērķa sasniegšanas posms, t.i. elements (objekts), kas ģenerēja notikumu.

Ņemot vērā visus notikuma posmus, rodas šāda aina:

Modifikēsim iepriekš minēto skripta piemēru šādi:

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

Trešais addEventListener un removeEventListener metožu parametrs nosaka posmu, kurā notikums tiks notverts. Ja šis parametrs ir iestatīts uz patiesu , notikums tiks pārtverts notikuma iegremdēšanas (pārtveršanas) posmā. Un, ja parametrs ir nepatiess , notikums tiks pārtverts burbuļošanas stadijā. Lai apstrādātu notikumu pašā mērķī, varat izmantot metodi addEventListener tāpat kā ar vērtība nepatiesa, un ar vērtību true .

Uzmanību: iegremdēšanas (pārtveršanas) posmā notikumus var pārtvert tikai apstrādātāji, kas pievienoti, izmantojot metodi addEventListener(). Apdarinātāji, kas pievienoti, izmantojot citas metodes ( HTML atribūts vai izmantojot JavaScript, izmantojot rekvizītu on[event]), var pārtvert notikumus tikai burbuļošanas stadijā.

Elementa iegūšana, kas ģenerēja notikumu

Lai iegūtu mērķa elementu, t.i. elementam, kas ģenerēja notikumu, ir jāizmanto mērķa rekvizīts (event.target).

Apsveriet iepriekš minēto piemēru, kurā mēs mainām skripta elementa saturu uz šādu:

Document.addEventListener("DOMContentLoaded", function() ( var elementBody = document.body; elementBody.addEventListener("click",function())( console.log(this.tagName + " — elements, kas izsauca apdarinātāju") ; konsole .log(event.currentTarget.tagName + " — elements, kas izsauca apdarinātāju"); console.log(event.target.tagName + " — elements, kas ģenerēja notikumu"); ),false); )) ;

Demonstrēsim mūsu piemēru, noklikšķinot ar peles kreiso taustiņu apgabalā, kas pieder spēcīgajam elementam:

Viss sākās ar JavaScript un klašu izmantošanu.

Tomēr man ir problēma. Es gribēju izmantot kaut ko, ko sauc par Bubble Events, taču vēlējos arī samazināt atkarības, kas man būtu jāinjicē. Es negribēju pieslēgties jQuery bibliotēkasšim mazajam testam, lai izmantotu uznirstošos notikumus.

Sīkāk apskatīsim, kas ir grauzdēšanas pasākumi, kā tie darbojas un daži veidi, kā tos īstenot.

Labi, kāda ir problēma? Apskatīsim vienkāršu piemēru:

Pieņemsim, ka mums ir pogu saraksts. Katru reizi, kad es noklikšķinu uz kāda no tiem, tam vajadzētu kļūt "aktīvam". Pēc atkārtotas nospiešanas pogai jāatgriežas sākotnējā stāvoklī.

Sāksim ar HTML:

  • Zīmulis
  • Pildspalva
  • dzēšgumija

Es varētu izmantot standarta JavaScript notikumu apstrādātāju, piemēram:

For(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"); }); }
Izskatās labi... Bet tas nedarbosies. Autors vismaz, ne tā, kā mēs to sagaidām.

Uzvar slēgšanas Tiem, kas zina nedaudz funkcionālu JavaScript, problēma ir acīmredzama.

Par pārējo es īsi paskaidrošu - apstrādātāja funkcija ir bloķēta pogas mainīgajam. Tomēr tas ir viens mainīgais, un tas tiek pārrakstīts katrā iterācijā.

Pirmajā iterācijā mainīgais attiecas uz pirmo pogu. Nākamajā - uz otro un tā tālāk. Bet, kad lietotājs noklikšķina uz pogas, cilpa jau ir beigusies, un pogas mainīgais attiecas uz pēdējo pogu, kas vienmēr izsauc notikumu apstrādātāju. Traucējumi.

Mums ir nepieciešams atsevišķs konteksts katrai funkcijai:

Var pogas = document.querySelectorAll(.rīkjoslas poga"); var createToolbarButtonHandler = funkcija(poga) ( atgriešanās funkcija() ( 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])); }
Daudz labāk! Un pats galvenais, tas darbojas pareizi. Mēs esam izveidojuši funkciju createToolbarButtonHandle, kas atgriež notikumu apdarinātāju. Pēc tam katrai pogai pievienojam savu apdarinātāju.

Kas tad par problēmu? Tas izskatās labi un darbojas. Neskatoties uz to, mēs joprojām varam uzlabot savu kodu.

Pirmkārt, mēs izveidojam pārāk daudz apstrādātāju. Katrai rīkjoslas pogai mēs izveidojam funkciju un saistām to kā notikumu apdarinātāju. Trīs pogām atmiņas lietojums ir niecīgs.

Bet, ja mums ir kaut kas līdzīgs šim:

  • Foo
  • Bārs
  • // ...vēl 997 elementi...
  • baz

tad dators, protams, neeksplodēs no pārplūdes. Tomēr mūsu atmiņas lietojums ir tālu no ideāla. Mēs to atvēlam milzīgu daudzumu, lai gan mēs varam iztikt bez tā. Pārrakstīsim savu kodu vēlreiz, lai vienu un to pašu funkciju varētu izmantot vairākas reizes.

Tā vietā, lai atsauktos uz pogas mainīgo, lai izsekotu, uz kuras pogas mēs noklikšķinājām, mēs varam izmantot notikuma objektu, kas tiek nodots kā pirmais arguments katram notikumu apstrādātājam.

Objektā Event ir daži dati par notikumu. Mūsu gadījumā mūs interesē pašreizējā Target lauks. No tā mēs saņemsim saiti uz elementu, uz kura tika noklikšķināts:

Var toolbarButtonHandler = funkcija(e) ( var poga = e.currentTarget; if(!button.classList.contains("active")) button.classList.add("aktīvs"); else button.classList.remove("active" ); ); for(var i = 0; i< buttons.length; i++) { button.addEventListener("click", toolbarButtonHandler); }
Lieliski! Mēs ne tikai esam vienkāršojuši visu līdz vienai funkcijai, kas tiek izmantota vairākas reizes, bet arī padarījuši mūsu kodu labāk lasāmu, noņemot nevajadzīgu ģeneratora funkciju.

Tomēr mēs joprojām varam darīt labāk.

Pieņemsim, ka pēc koda izpildes lapai pievienojām dažas pogas. Tad mums būtu jāpievieno arī notikumu apstrādātāji katram no tiem. Un mums būtu jāsaglabā saite uz šo apdarinātāju un saites no citām vietām. Neizskatās pārāk vilinoši.

Varbūt ir cita pieeja?

Sāksim ar izpratni par to, kā notikumi darbojas un kā tie virzās pa mūsu DOM.

Kā lielākā daļa no tiem darbojas? Kad lietotājs noklikšķina uz elementa, tiek ģenerēts notikums, lai par to informētu lietojumprogrammu. Katra notikuma ceļojums notiek trīs posmos:
  • Pārtveršanas fāze
  • Notikums notiek mērķa elementā
  • Pacelšanās fāze
  • Piezīme: ne visi notikumi tiek cauri pārtveršanas vai burbuļošanas stadijai; daži tiek izveidoti uzreiz elementā. Tomēr tas drīzāk ir noteikuma izņēmums.

    Notikums tiek izveidots ārpus dokumenta un pēc tam secīgi pārvietots pa DOM hierarhiju uz mērķa elementu. Kad tas ir sasniedzis mērķi, notikums tiek izgūts no DOM elementa tādā pašā veidā.

    Šeit ir mūsu HTML veidne:

    • Poga A
    • Poga B
    • Poga C

    Kad lietotājs noklikšķina uz pogas A, notikums notiek šādi:

    Sākt
    | #dokuments
    | Pārtveršanas fāze
    | HTML
    | BODY
    | UL
    | LI#li_1
    | Poga A< - Событие возникает для целевого элемента
    | Pacelšanās fāze
    | LI#li_1
    | UL
    | BODY
    | HTML
    v #dokuments

    Ievērojiet, ka mēs varam izsekot notikuma ceļam, lai sasniegtu mērķa elementu. Mūsu gadījumā par katru nospiesto pogu mēs varam būt pārliecināti, ka notikums atkal parādīsies uz augšu, izejot caur savu vecākelementu - ul elementu. Mēs varam to izmantot un ieviest uznirstošos notikumus.

    Burbuļa notikumi Burbuļa notikumi ir tie notikumi, kas ir pievienoti vecākelementam, bet tiek izpildīti tikai tad, ja tie atbilst kādam nosacījumam.

    Ņemsim mūsu rīkjoslu kā konkrētu piemēru:

    Ul class="rīkjosla">

  • Zīmulis
  • Pildspalva
  • dzēšgumija

  • Tagad, kad zinām, ka jebkurš klikšķis uz pogas tiks parādīts, izmantojot ul.toolbar elementu, pievienosim tam savu notikumu apdarinātāju. Par laimi, mums tas jau ir:

    Var rīkjosla = document.querySelector(.rīkjosla"); toolbar.addEventListener("klikšķis", funkcija(e) ( var poga = e.target; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList. noņemt("aktīvs"); ));
    Tagad mums ir daudz tīrāks kods, un mēs pat esam atbrīvojušies no cilpām! Tomēr ņemiet vērā, ka esam aizstājuši e.currentTarget ar e.target . Iemesls ir tas, ka mēs apstrādājam notikumus citā līmenī.

    e.target ir faktiskais notikuma mērķis, kur tas iziet cauri DOM un no kurienes tas sāks burbuļot.
    e.currentTarget — pašreizējais elements, kas apstrādā notikumu. Mūsu gadījumā šī ir ul.rīkjosla.

    Uzlaboti burbuļu pasākumi Šis brīdis Mēs apstrādājam jebkuru klikšķi uz katra elementa, kas tiek parādīts, izmantojot ul.toolbar , taču mūsu validācijas nosacījums ir pārāk vienkāršs. Kas notiktu, ja mums būtu sarežģītāks DOM, kurā būtu iekļautas ikonas un elementi, kas nav paredzēti noklikšķināšanai?

    • Zīmulis
    • Pildspalva
    • dzēšgumija

    Hmm! Tagad, kad mēs noklikšķinām uz li.separator vai ikonas, mēs pievienojam tai .active klasi. Vismaz tas nav labi. Mums ir nepieciešams veids, kā filtrēt notikumus, lai mēs reaģētu uz mums vajadzīgo elementu.

    Šim nolūkam izveidosim nelielu palīgfunkciju:

    Var deleģēt = function(kritēriji, klausītājs) ( atgriešanās funkcija(e) ( var el = e.target; do ( if (!criteria(el)) turpināt; e.delegateTarget = el; listener.apply(this, argumenti); atgriezties; ) while((el = el.parentNode)); ); );
    Mūsu palīgs dara divas lietas. Pirmkārt, tas atkārtos katru elementu un tā vecākiem un pārbaudīs, vai tie atbilst kritērija parametrā izvirzītajam nosacījumam. Ja elements atbilst prasībām, palīgs notikuma objektam pievieno lauku ar nosaukumu delegateTarget, kurā tiek saglabāts elements, kas atbilst mūsu nosacījumiem. Un tad zvana hendlerim. Attiecīgi, ja neviens elements neapmierina nosacījumu, neviens apstrādātājs netiks izsaukts.

    Mēs to varam izmantot šādi:

    Var rīkjosla = document.querySelector(.rīkjosla"); var buttonsFilter = function(elem) ( return elem.classList && elem.classList.contains("btn"); ); var buttonHandler = funkcija(e) ( var poga = e.delegateTarget; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active" ); ); toolbar.addEventListener("klikšķis", deleģēt(buttonsFilter, buttonHandler));
    Tieši tas, ko ārsts pasūtīja: viens notikumu apstrādātājs, kas piestiprināts vienam elementam, kas veic visu darbu. Bet tas to dara tikai tiem elementiem, kas mums nepieciešami. Un tas lieliski reaģē uz objektu pievienošanu un noņemšanu no DOM.

    Kopsavilkums Mēs īsi pārskatījām deleģēšanas (uznirstošo logu) notikumu ieviešanas pamatus tīrs JavaScript. Tas ir labi, jo mums nav jāģenerē un jāpievieno vairāki apstrādātāji katram elementam.

    Ja es vēlētos no tā izveidot bibliotēku vai izmantot kodu izstrādes procesā, es pievienotu dažas lietas:

    Palīdzības funkcija, lai pārbaudītu, vai objekts atbilst kritērijiem vienotākā un funkcionālākā formā. Patīk:

    Var kritēriji = ( isElement: function(e) ( atgriež e instanceof HTMLElement; ), hasClass: function(cls) ( atgriešanās funkcija(e) ( atgriešanās kritērijs.isElement(e) && e.classList.contains(cls); ) ) //Vairāk kritēriju);
    Noderētu arī daļēja asistenta izmantošana:

    Var partialDelgate = funkcija(kritēriji) ( atgriešanās funkcija(apdarinātājs) ( return delgate(kritēriji, apdarinātājs); ) );
    Sākotnējais raksts: Izpratne par deleģētajiem JavaScript notikumiem
    (No tulka: mans pirmais, spriediet stingri.)

    Laimīgu kodēšanu!

    Notikumi ir darbības vai notikumi, kas notiek jūsu programmētajā sistēmā, par ko sistēma jums paziņo, lai jūs varētu uz tiem kaut kādā veidā reaģēt, ja vēlaties. Piemēram, ja lietotājs tīmekļa lapā noklikšķina uz pogas, iespējams, vēlēsities reaģēt uz šo darbību, parādot informācijas lodziņu. Šajā rakstā mēs apspriežam dažus svarīgus jēdzienus, kas saistīti ar notikumiem, un aplūkojam, kā tie darbojas pārlūkprogrammās. Šis nebūs izsmeļošs pētījums; tikai ko tev vajag zināt šajā posmā.

    Priekšnosacījumi: Mērķis:
    Pamata datorprasmes, pamatzināšanas par HTML un CSS, JavaScript pirmie soļi.
    Izprast notikumu fundamentālo teoriju, to darbību pārlūkprogrammās un to, kā notikumi var atšķirties dažādās programmēšanas vidēs.
    Laimīgu notikumu virkne

    Kā minēts iepriekš, notikumi ir darbības vai notikumi, kas notiek sistēmā, kuru jūs programmējat — sistēma rada (vai "uzliesmo") sava veida signālu, kad notiek notikums, kā arī nodrošina mehānismu, ar kura palīdzību var veikt kādu darbību. automātiski tiek uzņemts (tas ir, kāds kods darbojas), kad notiek notikums. Piemēram, lidostā, kad skrejceļš ir brīvs, lai lidmašīna varētu pacelties, pilotam tiek paziņots signāls, un rezultātā viņi sāk vadīt lidmašīnu.

    Tīmekļa gadījumā notikumi tiek aktivizēti pārlūkprogrammas logā, un tie parasti tiek pievienoti konkrētam vienumam, kas tajā atrodas — tas var būt viens elements, elementu kopa, pašreizējā cilnē ielādēts HTML dokuments vai visu pārlūkprogrammas logu. Ir daudz dažādu notikumu, kas var notikt, piemēram:

    • Lietotājs, kas noklikšķina peles kursoru virs noteikta elementa vai novieto kursoru virs noteikta elementa.
    • Lietotājs nospiež taustiņu uz tastatūras.
    • Lietotājs maina pārlūkprogrammas loga izmēru vai aizver to.
    • Veidlapa tiek iesniegta.
    • Videoklips tiek atskaņots, apturēts vai tiek atskaņots.
    • Notiek kļūda.

    No šī (un skatoties uz MDN notikumu atsauci) varat secināt, ka ir daudz notikumu, uz kuriem var reaģēt.

    Katram pieejamajam notikumam ir notikumu apdarinātājs , kas ir koda bloks (parasti JavaScript funkcija, kuru izveidojat jūs kā programmētājs), kas tiks palaists, kad notikums tiks aktivizēts. Ja šāds koda bloks ir definēts tā, lai tas tiktu palaists, reaģējot uz notikuma aktivizēšanu, mēs sakām, ka mēs reģistrējam notikumu apstrādātāju . Ņemiet vērā, ka notikumu apstrādātājus dažreiz sauc par notikumu klausītājiem — tie ir diezgan savstarpēji aizstājami mūsu vajadzībām, lai gan stingri runājot, viņi strādā kopā. Klausītājs klausās, vai notikums notiek, un apstrādātājs ir kods, kas tiek palaists, reaģējot uz to, ka tas notiek.

    Piezīme. Tīmekļa notikumi nav daļa no JavaScript pamatvalodas — tie ir definēti kā daļa no pārlūkprogrammā iebūvētajām API.

    Vienkāršs piemērs

    Apskatīsim vienkāršu piemēru, lai izskaidrotu, ko mēs šeit domājam. Jūs jau esat redzējis notikumus un notikumu apstrādātājus, kas tiek izmantoti daudzos šī kursa piemēros, taču atkārtosim tikai, lai nostiprinātu mūsu zināšanas. Nākamajā piemērā mums ir singls , kuru nospiežot, fons mainās uz nejaušu krāsu:

    Mainīt krāsu

    Poga ( mala: 10 pikseļi );

    JavaScript izskatās šādi:

    Const btn = document.querySelector("poga"); funkcija nejaušs(skaitlis) ( atgriešanās Math.floor(Math.random() * (skaitlis+1)); ) btn.onclick = function() ( const rndCol = "rgb(" + random(255) + "," + nejaušs(255) + "," + nejaušs(255) + ")"; document.body.style.backgroundColor = rndCol; )

    Šajā kodā mēs saglabājam atsauci uz pogu konstantē ar nosaukumu btn , izmantojot funkciju Document.querySelector(). Mēs arī definējam funkciju, kas atgriež nejaušu skaitli. Koda trešā daļa ir notikumu apstrādātājs. Btn konstante norāda uz elementu, un šāda veida objektiem ir vairāki notikumi, kas var to aktivizēt, un tāpēc ir pieejami notikumu apstrādātāji. Mēs uzklausām klikšķa notikuma aktivizēšanu, iestatot onclick notikumu apdarinātāja rekvizītu vienādu ar anonīmu funkciju, kas satur kodu, kas ģenerē nejaušu RGB krāsu un iestata fona krāsu vienādu ar to.

    Šis kods tiek palaists ikreiz, kad elementā tiek aktivizēts klikšķa notikums, tas ir, ikreiz, kad lietotājs uz tā noklikšķina.

    Izvades piemērs ir šāds:

    Tās nav tikai tīmekļa lapas

    Vēl viena lieta, ko šajā brīdī ir vērts pieminēt, ir tas, ka notikumi nav unikāli JavaScript — lielākajai daļai programmēšanas valodu ir sava veida notikumu modelis, un modeļa darbības veids bieži atšķiras no JavaScript. Faktiski notikuma modelis JavaScript. tīmekļa lapām atšķiras no JavaScript notikumu modeļa, jo tas tiek izmantots citās vidēs.

    Iekļautie notikumu apstrādātāji — neizmantojiet tos

    Iespējams, savā kodā redzēsit arī šādu modeli:

    Nospiediet mani funkciju bgChange() ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol;)

    Agrākā tīmeklī atrastā notikumu apdarinātāju reģistrēšanas metode ietvēra notikumu apstrādātāja HTML atribūtus (vai iekļautos notikumu apdarinātājus ), piemēram, iepriekš parādīto — atribūta vērtība burtiski ir JavaScript kods, kuru vēlaties palaist, kad notiek notikums. Iepriekš minētajā piemērā tiek izsaukta funkcija, kas definēta elementā tajā pašā lapā, taču jūs varat arī ievietot JavaScript tieši atribūtā, piemēram:

    Nospied mani

    Jūs varat atrast HTML atribūtu ekvivalentus daudziem notikumu apstrādātāja rekvizītiem; Tomēr jūs tos nevajadzētu izmantot, jo tie tiek uzskatīti par sliktu praksi. Var šķist, ka ir viegli izmantot notikumu apstrādātāja atribūtu, ja jūs darāt kaut ko ļoti ātri, taču tie ļoti ātri kļūst nekontrolējami un neefektīvi.

    Sākumā nav ieteicams sajaukt HTML un JavaScript, jo to ir grūti parsēt — labāk ir saglabāt visu JavaScript vienuviet. ja tas ir atsevišķā failā, varat to lietot vairākiem HTML dokumentiem.

    Pat vienā failā iekļautie notikumu apstrādātāji nav laba ideja. Viena poga ir OK, bet kā būtu, ja jums būtu 100 pogas? Failam būtu jāpievieno 100 atribūti; tas ļoti ātri pārvērstos par apkopi. Izmantojot JavaScript, jūs varētu viegli murgi pievienot notikumu apstrādātāja funkciju visām lapas pogām neatkarīgi no tā, cik to ir, izmantojot kaut ko līdzīgu šis:

    Const pogas = document.querySelectorAll("poga"); for (lai i = 0; i< buttons.length; i++) { buttons[i].onclick = bgChange; } buttons.forEach(function(button) { button.onclick = bgChange; });

    Piezīme. Programmēšanas loģikas atdalīšana no satura arī padara jūsu vietni draudzīgāku meklētājprogrammām.

    addEventListener() un removeEventListener()

    Jaunākais notikumu mehānisma veids ir definēts Document Object Model (DOM) 2. līmeņa notikumu specifikācijā, kas nodrošina pārlūkprogrammas ar jaunu funkciju - addEventListener() . Tas darbojas līdzīgi notikumu apstrādātāja rekvizītiem, taču sintakse acīmredzami atšķiras. Mēs varētu pārrakstīt mūsu izlases krāsu piemēru, lai tas izskatītos šādi:

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

    Funkcijā addEventListener() mēs norādām divus parametrus - notikuma nosaukumu, kuram vēlamies reģistrēt šo apdarinātāju, un kodu, kas ietver apdarinātāja funkciju, kuru vēlamies palaist, reaģējot uz to. Ņemiet vērā, ka ir pilnīgi pareizi ievietot visu kodu funkcijā addEventListener() anonīmā funkcijā, piemēram:

    Btn.addEventListener("klikšķis", funkcija() ( var rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body .style.backgroundColor = rndCol; ));

    Šim mehānismam ir dažas priekšrocības salīdzinājumā ar iepriekš apspriestajiem vecākiem mehānismiem. Sākumā ir līdzvērtīga funkcija removeEventListener() , kas noņem iepriekš pievienoto klausītāju. Piemēram, tas noņemtu klausītāju kopu šīs sadaļas pirmajā koda blokā:

    Btn.removeEventListener("klikšķis", bgChange);

    Tas nav svarīgi vienkāršām, mazām programmām, taču lielākām, sarežģītākām programmām tas var uzlabot efektivitāti, tīrot vecos neizmantotos notikumu apdarinātājus. Turklāt, piemēram, tas ļauj vienai un tai pašai pogai veikt dažādas darbības dažādos apstākļos. viss, kas jums jādara, ir attiecīgi jāpievieno vai jānoņem notikumu apstrādātāji.

    Otrkārt, vienam un tam pašam klausītājam varat reģistrēt vairākus apdarinātājus. Abi šie apdarinātāji netiktu piemēroti:

    MyElement.onclick = funkcijaA; myElement.onclick = funkcijaB;

    Otrā rinda pārraksta pirmajā rindā iestatīto onclick vērtību. Tomēr tas darbotos:

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

    Noklikšķinot uz elementa, tagad darbosies abas funkcijas.

    Turklāt šim notikumu mehānismam ir pieejamas vairākas citas jaudīgas funkcijas un opcijas. Tie ir nedaudz ārpus šī raksta darbības jomas, taču, ja vēlaties tos izlasīt, apskatiet uzziņu lapas addEventListener() un removeEventListener().

    Kādu mehānismu man vajadzētu izmantot?

    No trim mehānismiem noteikti nevajadzētu izmantot HTML notikumu apstrādātāja atribūtus — tie ir novecojuši un ir slikta prakse, kā minēts iepriekš.

    Pārējie divi ir salīdzinoši savstarpēji aizstājami, vismaz vienkāršām vajadzībām:

    • Notikumu apstrādātāja rekvizītiem ir mazāka jauda un iespējas, taču labāka saderība ar dažādām pārlūkprogrammām (tiek atbalstīta līdz šim Internet Explorer 8). Mācoties, iespējams, jāsāk ar tiem.
    • DOM 2. līmeņa notikumi (addEventListener() u.c.) ir jaudīgāki, taču tie var kļūt arī sarežģītāki un mazāk atbalstīti (tiek atbalstīti jau pārlūkprogrammā Internet Explorer 9). Jums vajadzētu arī eksperimentēt ar tiem un censties tos izmantot, ja iespējams.

    Trešā mehānisma galvenās priekšrocības ir tādas, ka varat noņemt notikumu apstrādātāja kodu, ja nepieciešams, izmantojot removeEventListener() , un, ja nepieciešams, elementiem varat pievienot vairākus viena veida klausītājus. Piemēram, varat izsaukt addEventListener("klikšķis", funkcija() (... )) elementā vairākas reizes, otrajā argumentā norādot dažādas funkcijas. Tas nav iespējams ar notikumu apstrādātāja rekvizītiem, jo ​​visi turpmākie mēģinājumi iestatīt rekvizītu pārrakstīs agrākos, piemēram:

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

    Piezīme. Ja jūs savā darbā vēlaties atbalstīt pārlūkprogrammas, kas vecākas par Internet Explorer 8, jums var rasties grūtības, jo šādas senās pārlūkprogrammas izmanto atšķirīgus notikumu modeļus no jaunākām pārlūkprogrammām. Bet nekad nebaidieties, lielākajai daļai JavaScript bibliotēku (piemēram, jQuery) ir iebūvētas funkcijas, kas novērš atšķirības starp pārlūkprogrammām. Neuztraucieties par to pārāk daudz šajā mācību ceļojuma posmā.

    Citas pasākumu koncepcijas

    Šajā sadaļā mēs īsi aplūkojam dažus progresīvus jēdzienus, kas attiecas uz notikumiem. Šobrīd nav svarīgi pilnībā izprast šos jēdzienus, taču tie var kalpot, lai izskaidrotu dažus kodu modeļus, ar kuriem jūs, iespējams, ik pa laikam saskaraties.

    Pasākumu objekti

    Dažreiz notikumu apstrādātāja funkcijā var tikt parādīts parametrs, kas norādīts ar nosaukumu, piemēram, notikums , evt vai vienkārši e . To sauc par notikumu objektu, un tas tiek automātiski nodots notikumu apstrādātājiem, lai nodrošinātu papildu funkcijas un informāciju. Piemēram, vēlreiz nedaudz pārrakstīsim mūsu izlases krāsu piemēru:

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

    Šeit var redzēt, ka mēs funkcijā iekļaujam notikuma objektu e un funkcijā iestatām fona krāsas stilu uz e.target, kas ir pati poga. Notikuma objekta mērķa rekvizīts vienmēr ir atsauce uz elementu, kurā tikko noticis notikums. Tātad šajā piemērā mēs iestatām nejaušu fona krāsu pogai, nevis lapai.

    Piezīme. Notikuma objektam varat izmantot jebkuru nosaukumu, kas jums patīk — jums vienkārši jāizvēlas nosaukums, ko pēc tam varat izmantot, lai atsauktos uz to notikumu apstrādātāja funkcijā. e/evt/event visbiežāk izmanto izstrādātāji, jo tie ir īsi un viegli iegaumējami. Vienmēr ir labi būt konsekventam – ar sevi un, ja iespējams, ar citiem.

    e.target ir neticami noderīga, ja vēlaties iestatīt vienu un to pašu notikumu apdarinātāju vairākiem elementiem un kaut ko darīt ar tiem visiem, kad tajos notiek notikums. Piemēram, jums var būt 16 elementu komplekts, kas pazūd, kad uz tiem noklikšķina. Ir lietderīgi vienmēr vienkārši iestatīt lietu kā e.target tā, lai tā pazūd, nevis atlasīt to kādā sarežģītākā veidā. Nākamajā piemērā (skatiet visu avota kodu, lai iegūtu pilnu avota kodu, skatiet noderīgas-eventtarget.html; arī skatiet, kā tas darbojas tiešsaistē), izmantojot JavaScript, mēs izveidojam 16 elementus. Pēc tam mēs atlasām tos visus, izmantojot document.querySelectorAll() , pēc tam pārejam cauri katram, pievienojot katram onclick apdarinātāju, kas nodrošina, ka, noklikšķinot, katram tiek piemērota nejauša krāsa:

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

    Izvade ir šāda (mēģiniet noklikšķināt uz tā — izklaidējieties):

    Slēpts piemērs Noderīga notikuma mērķa piemērs div ( augstums: 100 pikseļi; platums: 25%; peldēšana: pa kreisi; ) for (lai i = 1; i
  • Zīmulis
  • Pildspalva
  • dzēšgumija

  • Tagad, kad zinām, ka jebkurš klikšķis uz pogas tiks parādīts, izmantojot ul.toolbar elementu, pievienosim tam savu notikumu apdarinātāju. Par laimi, mums tas jau ir:

    Var rīkjosla = document.querySelector(.rīkjosla"); toolbar.addEventListener("klikšķis", funkcija(e) ( var poga = e.target; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList. noņemt("aktīvs"); ));
    Tagad mums ir daudz tīrāks kods, un mēs pat esam atbrīvojušies no cilpām! Tomēr ņemiet vērā, ka esam aizstājuši e.currentTarget ar e.target . Iemesls ir tas, ka mēs apstrādājam notikumus citā līmenī.

    e.target ir faktiskais notikuma mērķis, kur tas iziet cauri DOM un no kurienes tas sāks burbuļot.
    e.currentTarget — pašreizējais elements, kas apstrādā notikumu. Mūsu gadījumā šī ir ul.rīkjosla.

    Uzlaboti uznirstošie notikumi Pašlaik mēs apstrādājam jebkuru klikšķi uz katra elementa, kas tiek parādīts, izmantojot ul.toolbar , taču mūsu apstiprināšanas nosacījums ir pārāk vienkāršs. Kas notiktu, ja mums būtu sarežģītāks DOM, kurā būtu iekļautas ikonas un elementi, kas nav paredzēti noklikšķināšanai?

    • Zīmulis
    • Pildspalva
    • dzēšgumija

    Hmm! Tagad, kad mēs noklikšķinām uz li.separator vai ikonas, mēs pievienojam tai .active klasi. Vismaz tas nav labi. Mums ir nepieciešams veids, kā filtrēt notikumus, lai mēs reaģētu uz mums vajadzīgo elementu.

    Šim nolūkam izveidosim nelielu palīgfunkciju:

    Var deleģēt = function(kritēriji, klausītājs) ( atgriešanās funkcija(e) ( var el = e.target; do ( if (!criteria(el)) turpināt; e.delegateTarget = el; listener.apply(this, argumenti); atgriezties; ) while((el = el.parentNode)); ); );
    Mūsu palīgs dara divas lietas. Pirmkārt, tas atkārtos katru elementu un tā vecākiem un pārbaudīs, vai tie atbilst kritērija parametrā izvirzītajam nosacījumam. Ja elements atbilst prasībām, palīgs notikuma objektam pievieno lauku ar nosaukumu delegateTarget, kurā tiek saglabāts elements, kas atbilst mūsu nosacījumiem. Un tad zvana hendlerim. Attiecīgi, ja neviens elements neapmierina nosacījumu, neviens apstrādātājs netiks izsaukts.

    Mēs to varam izmantot šādi:

    Var rīkjosla = document.querySelector(.rīkjosla"); var buttonsFilter = function(elem) ( return elem.classList && elem.classList.contains("btn"); ); var buttonHandler = funkcija(e) ( var poga = e.delegateTarget; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active" ); ); toolbar.addEventListener("klikšķis", deleģēt(buttonsFilter, buttonHandler));
    Tieši tas, ko ārsts pasūtīja: viens notikumu apstrādātājs, kas piestiprināts vienam elementam, kas veic visu darbu. Bet tas to dara tikai tiem elementiem, kas mums nepieciešami. Un tas lieliski reaģē uz objektu pievienošanu un noņemšanu no DOM.

    Kopsavilkums Mēs īsi apskatījām deleģēšanas (uznirstošo logu) notikumu ieviešanas pamatus tīrā JavaScript. Tas ir labi, jo mums nav jāģenerē un jāpievieno vairāki apstrādātāji katram elementam.

    Ja es vēlētos no tā izveidot bibliotēku vai izmantot kodu izstrādes procesā, es pievienotu dažas lietas:

    Palīdzības funkcija, lai pārbaudītu, vai objekts atbilst kritērijiem vienotākā un funkcionālākā formā. Patīk:

    Var kritēriji = ( isElement: function(e) ( atgriež e instanceof HTMLElement; ), hasClass: function(cls) ( atgriešanās funkcija(e) ( atgriešanās kritērijs.isElement(e) && e.classList.contains(cls); ) ) //Vairāk kritēriju);
    Noderētu arī daļēja asistenta izmantošana:

    Var partialDelgate = funkcija(kritēriji) ( atgriešanās funkcija(apdarinātājs) ( return delgate(kritēriji, apdarinātājs); ) );
    Sākotnējais raksts: Izpratne par deleģētajiem JavaScript notikumiem
    (No tulka: mans pirmais, spriediet stingri.)

    Laimīgu kodēšanu!

    Sveiki! Šajā nodarbībā es vēlos runāt par tik svarīgu jēdzienu kā notikumu atklāšana un pārtveršana. Burbuļošana ir parādība, kad, noklikšķinot uz pakārtota elementa, notikums tiek izplatīts uz tā vecāku.

    Tas var būt ļoti noderīgi, apstrādājot lielus ligzdotos sarakstus vai tabulas, lai katram elementam nepiešķirtu notikumu apdarinātāju, varat piešķirt vienu apdarinātāju vecākajam elementam, un notikums jau tiks izplatīts uz visiem ligzdotajiem elementiem vecākajā. Apskatīsim piemēru.

    Šis apdarinātājs tiks aktivizēts, ja noklikšķināsit uz apakštaga vai:

    Noklikšķiniet uz EM, darbosies DIV apstrādātājs

    Kā redzat, noklikšķinot uz ligzdotā em elementa, tiek aktivizēts div apdarinātājs. Kāpēc tas notiek? Lasi tālāk un uzzini.

    Pacelšanās

    Tātad pacelšanās pamatprincips:

    Ja notiek jebkāda veida notikums, nav nozīmes tam, vai pele tiek noklikšķināta uz elementa, notikums vispirms tiks aktivizēts vecākelementā, un pēc tam ķēdē tas tiks izplatīts uz visiem ligzdotajiem elementiem.

    Piemēram, pieņemsim, ka ir 3 ligzdoti elementi FORM > DIV > P, un katrā no tiem ir notikumu apdarinātājs:

    pamatteksts * (mala: 10 pikseļi; apmale: 1 pikseļi vienkrāsains zils; ) FORM DIV

    Burbuļošana nodrošina, ka noklikšķinot uz iekšējā elementa

    Vispirms izsauks klikšķu apdarinātāju (ja tāds, protams, pastāv).

    Šo procesu sauc par pacelšanos, jo šķiet, ka notikumi “uzpeld” no iekšējā elementa uz augšu caur saviem vecākiem, tāpat kā gaisa burbulis uzpeld ūdenī, tāpēc var atrast arī burbuļošanas definīciju, nu, tas ir tikai no angļu valodas. vārdu burbuļošana — uzpeldēt.

    Piekļuve mērķa elementam event.target

    Lai uzzinātu, kurā elementā mēs noķērām šo vai citu notikumu, ir metode event.target. (lasīt par pasākuma objektu).

    • event.target ir faktiskais avota elements, kurā notika notikums.
    • tas vienmēr ir pašreizējais elements, kuru ir sasniedzis burbuļošana, un apdarinātājs pašlaik darbojas tajā.

    Piemēram, ja jums ir instalēts tikai viens form.onclick apstrādātājs, tas “noķers” visus veidlapā veiktos klikšķus. Turklāt neatkarīgi no tā, kur atrodas klikšķis, tas joprojām parādīsies elementā, pie kura strādās apstrādātājs.

    Kurā:

    • šī (=event.currentTarget) vienmēr būs pati forma, jo apdarinātājs strādāja pie tās.
    • Event.target satur saiti uz konkrētu veidlapas elementu, visvairāk ligzdoto elementu, uz kura tika veikts klikšķis.

    Principā tas var sakrist ar event.target, ja tiek noklikšķināts uz veidlapas un formā vairs nav elementu.

    Apstāšanās kāpiens

    Parasti notikumu burbuļošana iet tieši uz augšu un sasniedz saknes loga objektu.

    Bet ir iespējams apturēt kāpumu pie kāda starpelementa.

    Lai apturētu izplatīšanu, ir jāizsauc metode event.stopPropagation().

    Apskatīsim piemēru: noklikšķinot uz pogas, body.onclick apstrādātājs nedarbosies:

    Noklikšķiniet uz manis

    Ja elementam vienam un tam pašam notikumam ir instalēti vairāki apstrādātāji, pat tad, ja burbuļošana apstājas, tiks izpildīti visi.

    Tādējādi stopPropagation neļaus notikumam izplatīties tālāk, taču visi apstrādātāji strādās pie elementa, bet ne ar nākamo elementu.

    Lai apturētu pašreizējā elementa apstrādi, pārlūkprogrammas atbalsta metodi event.stopImmediatePropagation(). Šī metode ne tikai novērsīs burbuļošanu, bet arī apturēs notikumu apstrādi pašreizējā elementā.

    Niršana

    Standartā papildus notikumu “pacelšanās” ir arī “niršana”.

    Niršana, atšķirībā no pacelšanās, ir mazāk pieprasīta, taču vienalga par to būs noderīgi uzzināt.

    Tātad pasākumam ir 3 posmi:

  • Pasākums nāk no augšas uz leju. Šo posmu sauc par "pārtveršanas stadiju".
  • Pasākums sasniedza konkrētu elementu. Šī ir "mērķa stadija".
  • Pēc visa, notikums sāk parādīties. Šis ir "pacelšanās posms".
  • Tas ir parādīts standartā šādi:

    Tādējādi, noklikšķinot uz TD, notikums virzīsies pa vecāku ķēdi, vispirms uz leju līdz elementam (“nogrimst”) un pēc tam uz augšu (“uznirst”), pa ceļam attiecīgi izmantojot apstrādātājus.

    Augstāk rakstīju tikai par kāpumu, jo pārējie ātrumposmi netiek izmantoti un paiet mums nepamanīti.

    Hendleri neko nezina par pārtveršanas posmu, bet sāk strādāt no kāpuma.

    Un, lai uztvertu notikumu pārtveršanas stadijā, jums vienkārši jāizmanto:

    • Arguments ir patiess, tad notikums tiks pārtverts lejā.
    • Arguments ir nepatiess, tad notikums tiks noķerts burbuļojot.
    Piemēri

    Piemērā , ,

    Procesori ir tādi paši kā iepriekš, bet šoreiz iegremdēšanas stadijā. Nu, lai redzētu pārtveršanu darbībā, noklikšķiniet uz elementa tajā

    Apdarinātāji strādās secībā no augšas uz leju: FORMA → DIV → P.

    JS kods šeit ir:

    Var elems = document.querySelectorAll("forma,div,p"); // pievienot apdarinātāju katram elementam pārtveršanas stadijā (var i = 0; i< elems.length; i++) { elems[i].addEventListener("click", highlightThis, true); }


    Neviens neliedz jums piešķirt apdarinātājus abiem posmiem, piemēram:

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

    Noklikšķiniet uz iekšējā elementa

    Lai redzētu notikumu secību:
    Tam vajadzētu būt FORMA → DIV → P → P → DIV → FORM. Ņemiet vērā, ka elements

    Piedalīsies abos posmos.

    Rezultāti
    • Kad notiek notikums, elements, kurā notika notikums, tiek atzīmēts kā event.target.
    • Notikums vispirms pārvietojas uz leju no dokumenta saknes uz event.target, izsaucot apstrādātājus, kas tiek nodrošināti, izmantojot addEventListener (…., true).
    • Notikums tiek pārvietots no event.target uz dokumenta sākumu, vienlaikus izsaucot apstrādātājus, kas nodrošināti, izmantojot addEventListener (…., false).

    Katrs apstrādātājs varēs piekļūt notikuma rekvizītiem:

    • event.target ir dziļākais elements, kurā notikums faktiski notika.
    • event.currentTarget (=this) – elements, uz kura pašlaik tiek iedarbināts pašapkalpotājs (kuru notikums ir “sasniedzis”).
    • event.eventPhase – kurā fāzē tika iedarbināts notikumu apstrādātājs (dive = 1, ascend = 3).

    Izplatīšanu var apturēt, izsaucot metodi event.stopPropagation(), taču tas nav ieteicams, jo notikums var būt nepieciešams neparedzētākajiem mērķiem.