Js esemény bugyborékol. Speciális munka az Event objektummal JavaScriptben. Bevezetés a delegációba

Az események olyan műveletek vagy események, amelyek a programozott rendszerben történnek, és amelyekről a rendszer tájékoztat, így kívánság szerint reagálni tud rájuk. Például, ha a felhasználó rákattint egy gombra egy weboldalon, akkor a műveletre egy információs mező megjelenítésével válaszolhat. Ebben a cikkben az eseményekkel kapcsolatos néhány fontos fogalmat tárgyalunk, és megvizsgáljuk, hogyan működnek ezek a böngészőkben. Ez nem egy kimerítő tanulmány, csupán annyit kell tudnia ebben a szakaszban.

Előfeltételek: Célkitűzés:
Alapvető számítógépes ismeretek, HTML és CSS alapismeretek, JavaScript első lépései.
Megérteni az események alapvető elméletét, hogyan működnek a böngészőkben, és hogyan különbözhetnek az események a különböző programozási környezetekben.
Szerencsés események sorozata

Ahogy fentebb említettük, az események olyan cselekvések vagy események, amelyek a programozott rendszerben történnek – a rendszer valamilyen jelet ad ki (vagy "kigyújt"), amikor egy esemény bekövetkezik, és egy olyan mechanizmust is biztosít, amellyel valamilyen cselekvés végrehajtható. automatikusan veszik (vagyis valamilyen kód fut), amikor az esemény bekövetkezik. Például egy repülőtéren, amikor a kifutópálya szabad a felszállás előtt, jelzést küldenek a pilótának, és ennek eredményeként megkezdik a gép vezetését.

A web esetében az események a böngészőablakon belül indulnak el, és általában egy adott elemhez kapcsolódnak, amely abban található - ez lehet egyetlen elem, elemkészlet, az aktuális lapon betöltött HTML-dokumentum, vagy a teljes böngészőablakot. Nagyon sokféle esemény fordulhat elő, például:

  • A felhasználó az egeret egy bizonyos elemre kattintva, vagy a kurzort egy bizonyos elem fölé viszi.
  • A felhasználó megnyom egy billentyűt a billentyűzeten.
  • A felhasználó átméretezi vagy bezárja a böngészőablakot.
  • Űrlap benyújtása folyamatban.
  • Videó lejátszása, szüneteltetése vagy a lejátszás befejezése.
  • Hiba történt.

Ebből (és az MDN Event referenciájára pillantva) megállapítható, hogy nagyon sok eseményre lehet reagálni.

Minden elérhető eseménynek van eseménykezelője , amely egy kódblokk (általában egy JavaScript függvény, amelyet programozóként Ön hoz létre), amely az esemény aktiválásakor fut le. Ha egy ilyen kódblokkot úgy határozunk meg, hogy egy esemény aktiválására válaszul lefusson, akkor azt mondjuk, hogy eseménykezelőt regisztrálunk. Ne feledje, hogy az eseménykezelőket néha eseményfigyelőknek is nevezik – céljainkban nagyjából felcserélhetők, bár szigorúan véve együtt dolgoznak. A figyelő figyel az eseményre, és a kezelő a kód, amely válaszul lefut az eseményre.

Megjegyzés: A webes események nem részei a JavaScript alapnyelvének – a böngészőbe épített API-k részeként vannak meghatározva.

Egy egyszerű példa

Tekintsünk egy egyszerű példát, hogy megmagyarázzuk, mire gondolunk. Sok példában már láthatta az eseményeket és az eseménykezelőket, de nézzük csak meg, hogy megerősítsük tudásunkat a következőket Például van egy , amelyet megnyomva a háttér véletlenszerű színre változik:

Szín módosítása

Gomb ( margó: 10 képpont );

A JavaScript így néz ki:

Const btn = document.querySelector("button"); függvény random(szám) ( return Math.floor(Math.random() * (szám+1)); ) btn.onclick = function() ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol )

Ebben a kódban a Document.querySelector() függvény segítségével egy btn nevű állandóban tárolunk egy hivatkozást a gombra. Definiálunk egy függvényt is, amely véletlen számot ad vissza. A kód harmadik része az eseménykezelő. A btn konstans egy elemre mutat, és az ilyen típusú objektumok számos eseményt aktiválhatnak, és ezért eseménykezelők is elérhetők. Figyeljük a kattintási esemény aktiválását úgy, hogy az onclick eseménykezelő tulajdonságot egy névtelen függvényre állítjuk, amely kódot tartalmaz, amely véletlenszerű RGB színt generál, és ezzel egyenlőre állítja a háttérszínt.

Ez a kód akkor fut le, amikor a kattintási esemény aktiválódik az elemen, vagyis amikor a felhasználó rákattint.

A példa kimenete a következő:

Nem csak weboldalakról van szó

Egy másik dolog, amit érdemes megemlíteni ezen a ponton, hogy az események nem egyediek a JavaScriptben – a legtöbb programozási nyelvnek van valamilyen eseménymodellje, és a modell működése gyakran eltér a JavaScripttől. Valójában az eseménymodell a JavaScriptben weboldalak esetében eltér a JavaScript eseménymodelljétől, mivel azt más környezetekben használják.

Soron belüli eseménykezelők – ne használja ezeket

Egy ehhez hasonló mintát is láthat a kódjában:

Nyomja meg a bgChange() függvényt ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol )

Az eseménykezelők regisztrálásának legkorábbi módja a weben olyan eseménykezelő HTML attribútumokat (vagy soron belüli eseménykezelőket) tartalmazott, mint pl. az egy fent látható - az attribútum értéke szó szerint az a JavaScript-kód, amelyet az esemény bekövetkezésekor futtatni szeretne. A fenti példa egy ugyanazon az oldalon lévő elemen belül definiált függvényt hív meg, de közvetlenül az attribútumba is beillesztheti a JavaScriptet, például:

Nyomja meg

Számos eseménykezelő tulajdonsághoz találhat HTML attribútum-ekvivalenseket; ezeket azonban nem szabad használni – rossz gyakorlatnak számítanak. Lehet, hogy egyszerűnek tűnhet az eseménykezelő attribútum használata, ha valamit nagyon gyorsan csinálsz, de nagyon gyorsan kezelhetetlenné és hatástalanná válnak.

Kezdetben nem jó ötlet összekeverni a HTML-kódot és a JavaScriptet, mivel nehéz lesz elemezni – jobb, ha a JavaScriptet egy helyen tartja; ha külön fájlban van, akkor több HTML dokumentumra is alkalmazhatja.

A soron belüli eseménykezelők még egyetlen fájlban sem jó ötlet. Egy gomb rendben van, de mi lenne, ha 100 gombja lenne? 100 attribútumot kell hozzáadnia a fájlhoz; ez nagyon gyorsan karbantartási munkává válna. A JavaScript használatával könnyen rémálomszerű lehet eseménykezelő funkciót hozzáadni az oldal összes gombjához, függetlenül attól, hogy hányan vannak, például ez:

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

Megjegyzés: A programozási logika és a tartalom elkülönítése a keresőmotorok számára is barátságosabbá teszi webhelyét.

addEventListener() és removeEventListener()

Az eseménymechanizmus legújabb típusát a Document Object Model (DOM) 2. szintű eseményspecifikációja határozza meg, amely egy új funkcióval látja el a böngészőket - addEventListener() . Ez hasonló módon működik, mint az eseménykezelő tulajdonságai, de a szintaxis nyilvánvalóan más. A véletlenszerű színpéldánkat átírhatjuk a következőre:

Const btn = document.querySelector("button"); function bgChange() ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol; ) btn.addEventListener("kattintás", bgChange);

Az addEventListener() függvényen belül két paramétert adunk meg - annak az eseménynek a nevét, amelyhez ezt a kezelőt regisztrálni akarjuk, és a kódot, amely tartalmazza a kezelő függvényt, amelyet válaszul futtatni szeretnénk. Vegye figyelembe, hogy tökéletesen helyénvaló az összes kódot az addEventListener() függvénybe, egy névtelen függvénybe helyezni, például:

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

Ennek a mechanizmusnak van néhány előnye a korábban tárgyalt régebbi mechanizmusokhoz képest. Kezdetnek van egy megfelelő függvény, a removeEventListener() , amely eltávolítja a korábban hozzáadott figyelőt. Ez például eltávolítja a figyelőkészletet az első kódblokkban ebben a szakaszban:

Btn.removeEventListener("kattintás", bgChange);

Ez az egyszerű, kis programok esetében nem jelentős, de nagyobb, összetettebb programok esetén javíthatja a hatékonyságot a régi, használaton kívüli eseménykezelők tisztítása, valamint például lehetővé teszi, hogy ugyanaz a gomb különböző körülmények között különböző műveleteket hajtson végre. mindössze annyit kell tennie, hogy adott esetben hozzáadja vagy eltávolítja az eseménykezelőket.

Másodszor, több kezelőt is regisztrálhat ugyanahhoz a figyelőhöz. A következő két kezelő mindkettőt nem alkalmazza:

MyElement.onclick = functionA; myElement.onclick = functionB;

A második sor felülírja az első sor által beállított onclick értékét. Ez azonban működne:

MyElement.addEventListener("kattintás", függvényA); myElement.addEventListener("kattintás", függvényB);

Mindkét funkció futni fog, ha az elemre kattintanak.

Ezen kívül számos más hatékony funkció és opció érhető el ezzel az eseménymechanizmussal. Ezek egy kicsit kívül esnek ebben a cikkben, de ha többet szeretne olvasni róluk, tekintse meg az addEventListener() és removeEventListener() hivatkozási oldalakat.

Milyen mechanizmust használjak?

A három mechanizmus közül semmiképpen ne használja a HTML eseménykezelő attribútumait – ezek elavultak és rossz gyakorlatok, ahogy fentebb említettük.

A másik kettő viszonylag felcserélhető, legalábbis egyszerű használatra:

  • Az eseménykezelő tulajdonságok kevesebb energiával és lehetőségekkel rendelkeznek, de jobb a böngészők közötti kompatibilitás (ami eddig támogatott Internet Explorer 8). Valószínűleg ezekkel kellene kezdenie a tanulás során.
  • A DOM 2. szintű események (addEventListener() stb.) erősebbek, de összetettebbé is válhatnak, és kevésbé támogatottak (az Internet Explorer 9-ig támogatott). Érdemes ezekkel is kísérletezni, és lehetőség szerint törekedni a használatára.

A harmadik mechanizmus fő előnye, hogy szükség esetén eltávolíthatja az eseménykezelő kódját a removeEventListener() segítségével, és szükség esetén több azonos típusú figyelőt is hozzáadhat az elemekhez. Például az addEventListener("click", function() ( ... )) függvényt többször is meghívhatja egy elemen, a második argumentumban különböző függvényekkel. Ez az eseménykezelő tulajdonságaival lehetetlen, mert minden későbbi kísérlet egy tulajdonság beállítására felülírja a korábbiakat, pl.:

Element.onclick = függvény1; element.onclick = függvény2; stb.

Megjegyzés: Ha munkája során az Internet Explorer 8-nál régebbi böngészők támogatását kérik, nehézségekbe ütközhet, mivel az ilyen régi böngészők az újabb böngészőktől eltérő eseménymodelleket használnak. De soha ne féljen, a legtöbb JavaScript-könyvtár (például a jQuery) rendelkezik olyan beépített funkciókkal, amelyek absztrahálják a böngészők közötti különbségeket. Ne aggódjon emiatt túl sokat tanulási útja ezen szakaszában.

Egyéb eseményfogalmak

Ebben a részben röviden bemutatunk néhány fejlett fogalmat, amelyek az események szempontjából relevánsak. Nem fontos, hogy ezen a ponton teljesen megértsük ezeket a fogalmakat, de megmagyarázhatnak néhány kódmintát, amellyel valószínűleg időnként találkozni fog.

Eseményobjektumok

Előfordulhat, hogy az eseménykezelő függvényen belül olyan paramétert láthat, amely olyan néven van megadva, mint event , evt vagy egyszerűen e . Ezt eseményobjektumnak nevezik, és automatikusan átadják az eseménykezelőknek, hogy további szolgáltatásokat és információkat biztosítsanak. Például írjuk át kicsit újra a véletlenszerű színpéldánkat:

Függvény bgChange(e) ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; e.target.style.backgroundColor = rndCol console.log(e); btn.addEventListener("click", bgChange);

Itt látható, hogy a függvényben egy eseményobjektumot, e , a függvényben pedig háttérszínstílust állítunk be az e.target-en - ami maga a gomb. Az eseményobjektum céltulajdonsága mindig egy hivatkozás arra az elemre, amelyen az esemény éppen bekövetkezett. Tehát ebben a példában véletlenszerű háttérszínt állítunk be a gombhoz, nem az oldalhoz.

Megjegyzés: Bármilyen nevet használhat az eseményobjektumhoz – csak ki kell választania egy nevet, amellyel hivatkozhat rá az eseménykezelő funkción belül. A fejlesztők leggyakrabban az e/evt/event fájlt használják, mert rövidek és könnyen megjegyezhetőek. Mindig jó következetesnek lenni – önmagával és lehetőség szerint másokkal is.

Az e.target hihetetlenül hasznos, ha ugyanazt az eseménykezelőt több elemre szeretné beállítani, és mindegyikkel tenni szeretne valamit, amikor esemény történik rajtuk. Lehet például egy 16 lapkából álló készlet, amely eltűnik, ha rájuk kattintanak. Hasznos, ha mindig beállíthatjuk, hogy a dolog eltűnjön e.targetként, ahelyett, hogy valami bonyolultabb módon kellene kiválasztani. A következő példában (a teljes forráskódért lásd a hasznos-eventtarget.html oldalt; itt láthatja élőben is) 16 elemet hozunk létre JavaScript használatával. Ezután mindegyiket kijelöljük a document.querySelectorAll() segítségével, majd mindegyiket végigfutjuk, és mindegyikhez hozzáadunk egy onclick kezelőt, amivel véletlenszerű színt alkalmazunk mindegyikre kattintáskor:

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

A kimenet a következő (kattintson rá – jó szórakozást):

Rejtett példa Hasznos eseménycélpélda div ( magasság: 100 képpont; szélesség: 25%; lebegés: balra; ) for (legyen i = 1; i DIV > P , mindegyiken egy kezelővel:

Kód: FORM
DIV

A buborékolás biztosítja, hogy a belső felületre kattintsanak

Először az onclick kezelőt hívja (ha van ilyen).

Ezért, ha a fenti példában rákattint a P-re, akkor a figyelmeztetés sorban jelenik meg: p → div → form.

Ezt a folyamatot felemelkedésnek nevezik, mert az események „lebegnek” a belső elemtől felfelé a szülőkön keresztül, ahogyan egy légbuborék lebeg a vízben.

esemény.célpont

Mindegy, hogy melyik elemen fogjuk meg az eseményt, mindig megtudhatjuk, hogy pontosan hol történt.
Az eseményt elindító legmélyebb elemet "cél" vagy "forrás" elemnek nevezik, és event.target néven érhető el.

Eltérések ettől (=event.currentTarget):

  • event.target az eredeti elem, amelyen az esemény történt, változatlan marad a buborékolási folyamat során.
  • ez az az aktuális elem, amelyet a buborékolás elért, és jelenleg fut rajta.

Például, ha csak egy form.onclick kezelő van, akkor az „elfog” minden kattintást az űrlapon belül. Ahol van bent egy kattintás, felugrik arra az elemre, amelyen a kezelő fog dolgozni.

Ebben az esetben:

  • ez (=event.currentTarget) mindig maga az űrlap lesz, mivel a kezelőt ezen aktiválták.
  • Az event.target egy hivatkozást tartalmaz az űrlapon belül egy adott elemre, arra a leginkább beágyazott elemre, amelyen a kattintás történt.

Az is előfordulhat, hogy az event.target és ez ugyanaz az elem, például ha nincs más címke az űrlapon, és a kattintás magára az elemre történt.

Egy esemény bugyborékolásának leállítása

Az emelkedés egyenesen a csúcsra megy. Általában az esemény felfelé és felfelé buborékol, az elemhez, majd a dokumentumhoz, és néha még az ablakhoz is, miközben az összes kezelőt meghívja.

De bármely köztes kezelő eldöntheti, hogy az eseményt teljesen feldolgozták, és leállíthatja a buborékolást.

A terjedés leállításához meg kell hívni az event.stopPropagation() metódust.

Például itt, amikor egy gombra kattintanak, a body.onclick kezelő nem fog működni:

Kód:
Kattintson rám

Esemény elfogás. event.stopImmediatePropagation()

Ha egy elemnek több kezelője van egy eseményhez, akkor még ha a buborékolás leáll, mindegyik végrehajtásra kerül.

Vagyis a stopPropagation megakadályozza az esemény előrehaladását, de minden kezelő az aktuális elemen dolgozik.

A feldolgozás teljes leállításához, modern böngészők támogatja az event.stopImmediatePropagation() metódust. Nemcsak a buborékolást akadályozza meg, hanem leállítja az eseményfeldolgozást is az aktuális elemen.

Különbségek IE8-

A könnyebb eligazodás érdekében egy részbe gyűjtöttem az IE8-különbségeket, amelyek a felszínre kerüléshez kapcsolódnak.

Tudásukra szükség lesz, ha úgy dönt, hogy tiszta JS-ben ír, keretrendszerek nélkül, és szüksége van IE8 támogatásra.

Nincs event.currentTarget tulajdonság

Felhívjuk figyelmét, hogy az on property-n keresztüli kezelő hozzárendelésénél ez van, tehát az event.currentTarget -re általában nincs szükség, de az attachEvent -en keresztüli hozzárendelésnél a kezelő ezt nem kapja meg, így az aktuális elemet, ha szükséges, csak lezárásokból vehetők át.

Az IE8-ban az event.target helyett az event.srcElement kerül felhasználásra

Ha olyan kezelőt írunk, amely támogatja az IE8-at és a modern böngészőket is, akkor a következőképpen indíthatjuk el:

Kód: elem.onclick = function(event) (
esemény = esemény || ablak.esemény;
var target = event.target || event.srcElement;

// ...most van egy eseményobjektum és egy célpontunk
...
}

Az emelkedés leállításához használja az event.cancelBubble=true kódot

A következőképpen állíthatja le a keresztböngésző buborékolását:

Kód: event.stopPropagation ? event.stopPropagation() : (event.cancelBubble=true);

Teljes
  • Amikor egy esemény bekövetkezik, azt az elemet, amelyen az történt, „target”-ként (event.target) jelöljük.
  • Ezután az esemény először a dokumentumgyökérről lefelé halad az event.target-be, az addEventListener(.... igaz, igaz) által biztosított kezelők meghívásával együtt.
  • Ezután az esemény az event.target-ből a dokumentumgyökérbe kerül, miközben meghívja az on* és addEventListener(...., false) kezelőket.
  • Az event.target a legmélyebb elem, amelyen az esemény bekövetkezett.
  • event.currentTarget (=this) – az az elem, amelyen pillanatnyilag a kezelő (amelyet az esemény elért) kiváltott.
  • event.eventPhase – melyik fázisban váltott ki (merülés = 1, emelkedés = 3).
Esemény elfogás

A nyelv egyik fontos jellemzője az események lehallgatása. Ha például valaki rákattint egy gombra, akkor az adott gombhoz tartozó onClick eseménykezelő meghívódik. Az eseménykezeléssel biztosíthatja, hogy az ablaknak, dokumentumnak vagy fóliának megfelelő objektum elfogjon és feldolgozzon egy eseményt, mielőtt az eseménykezelőt a megadott gombobjektum erre a célra hívná. Hasonlóképpen, az ablak, a dokumentum vagy a fóliaobjektum még azelőtt képes feldolgozni egy eseményjelet, hogy az elérné normál célját.
Ha látni szeretné, mire lehet ez hasznos, nézzük meg a következő példát:



window.onclick=handle;

függvény fogantyú(e) (
alert("Az ablak objektum elfogja ezt az eseményt!");
return true; // azaz kövesse a linket
}




Kattintson erre a linkre

Mint látható, nem adunk meg eseménykezelőket a címkében . Ehelyett írunk

window.captureEvents(Event.CLICK);

az esemény lehallgatása érdekében Kattintson ablak objektum. Általában az ablak objektum nem működik együtt az eseménnyel Kattintson. Azonban miután elfogtuk, átirányítjuk az ablak objektumra. Vegye figyelembe, hogy be Esemény.KATTINTÁS töredék KATTINTÁS nagybetűvel kell írni. Ha több eseményt szeretne lehallgatni, válassza el őket egymástól a | szimbólumokkal. Például:

window.captureEvents(Event.CLICK | Event.MOVE);

Ezen kívül a függvényben fogantyú(), amelyet az eseménykezelő szerepkörhöz rendeltünk, az utasítást használjuk return true;. Ez valójában azt jelenti, hogy a böngészőnek magát a hivatkozást kell feldolgoznia a funkció befejezése után. fogantyú(). Ha írsz helyette return false;, akkor ennek az egésznek vége lesz.

Ha most a címkében Meg kell adni egy eseménykezelőt onClick, meg fogja érteni, hogy ez a program a továbbiakban nem lesz meghívva, amikor ez az esemény bekövetkezik. Ez nem meglepő, mivel az ablak objektum elfogja az eseményjelet, mielőtt az elérné a link objektumot. Ha definiál egy függvényt fogantyú() Hogyan

függvény fogantyú(e) (
alert("Az ablak objektum rögzítette ezt az eseményt!");
window.routeEvent(e);
return true;
}

akkor a számítógép ellenőrzi, hogy más eseménykezelők vannak-e definiálva ehhez az objektumhoz. Az e változó az Event objektumunk, amelyet argumentumként adunk át az esemény függvénynek.

Ezenkívül közvetlenül küldhet eseményjelet egy objektumnak. Ehhez használhatja a módszert handleEvent(). Így néz ki:


window.captureEvents(Event.CLICK);

window.onclick=handle;

függvény fogantyú(e) (
document.links.handleEvent(e);
}


"Kattintson" erre a linkre

Második link

Minden Click eseményjel a második linkre kerül feldolgozásra – még akkor is, ha egyáltalán nem kattintott egyik linkre sem!

A következő szkript bemutatja, hogy a szkript hogyan tud reagálni a billentyűleütési jelekre. Nyomja meg bármelyik billentyűt, és nézze meg, hogyan működik ez a szkript.


window.captureEvents(Event.KEYPRESS);

window.onkeypress= lenyomva;

funkció megnyomva (e) (
alert("A gomb lenyomva! ASCII-érték: " + e.which);
}

Az egész a JavaScript és az osztályok használatával kezdődött.

Van azonban egy problémám. Használni akartam valamit, amit Bubble Eventsnek hívnak, de minimálisra akartam csökkenteni a függőséget, amelyet be kell szúrnom. Nem akartam jQuery-könyvtárakat hozzáadni ehhez a kis teszthez, csak az eseménybuborékok használatához.

Nézzük meg közelebbről, mik azok a pirítós események, hogyan működnek, és néhány módszert a megvalósításukra.

Oké, akkor mi a probléma? Nézzünk egy egyszerű példát:

Tegyük fel, hogy van egy gomblistánk. Minden alkalommal, amikor rákattintok valamelyikre, "aktívvá" kell válnia. Újabb megnyomás után a gombnak vissza kell térnie az eredeti állapotába.

Kezdjük a HTML-el:

  • Ceruza
  • Toll
  • radír

Használhatok egy szabványos JavaScript eseménykezelőt, mint például:

For(i változó = 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"); }); }
Jól néz ki... De nem fog menni. Legalábbis nem úgy, ahogy várjuk.

A bezárások nyernek Azok számára, akik ismerik egy kicsit a funkcionális JavaScriptet, a probléma nyilvánvaló.

A többit röviden elmagyarázom - a kezelő funkció a gombváltozóhoz van zárva. Ez azonban egyetlen változó, és minden iterációnál felülíródik.

Az első iterációban a változó az első gombra hivatkozik. A következőben - a másodikra ​​és így tovább. De amikor a felhasználó rákattint a gombra, a ciklus már véget ért, és a gombváltozó az utolsó gombra hivatkozik, amely mindig hívja az eseménykezelőt. Zavar.

Minden funkcióhoz külön kontextusra van szükségünk:

Var gombok = document.querySelectorAll(.toolbar button"); var createToolbarButtonHandler = function(button) ( return function() ( if(!button.classList.contains("active")) button.classList.add("aktív"); else button.classList.remove("aktív"); ); for(i változó = 0; i< buttons.length; i++) { buttons[i].addEventListener("click", createToolBarButtonHandler(buttons[i])); }
Sokkal jobb! És ami a legfontosabb, megfelelően működik. Létrehoztunk egy createToolbarButtonHandle függvényt, amely eseménykezelőt ad vissza. Ezután minden gombhoz csatoljuk a saját kezelőt.

Szóval mi a probléma? Jól néz ki és működik. Ennek ellenére még mindig javíthatjuk a kódunkat.

Először is túl sok kezelőt hozunk létre. Az eszköztáron belül minden egyes gombhoz létrehozunk egy függvényt, és eseménykezelőként kötjük össze. Három gomb esetén a memóriahasználat elhanyagolható.

De ha van valami ilyesmi:

  • Foo
  • Bár
  • // ...még 997 elem...
  • baz

akkor a számítógép természetesen nem fog felrobbanni a túlcsordulástól. A memóriahasználatunk azonban távolról sem ideális. Hatalmas mennyiséget osztunk ki belőle, bár megtehetjük nélküle is. Írjuk újra a kódunkat, hogy ugyanazt a függvényt többször is használhassuk.

Ahelyett, hogy a gombváltozóra hivatkoznánk annak nyomon követésére, hogy melyik gombra kattintottunk, használhatunk egy eseményobjektumot, amely első argumentumként kerül átadásra minden eseménykezelőnek.

Az Event objektum néhány adatot tartalmaz az eseményről. Esetünkben a currentTarget mező érdekel bennünket. Ebből kapunk egy linket arra az elemre, amelyre kattintottak:

Var toolbarButtonHandler = function(e) ( var gomb = e.currentTarget; if(!button.classList.contains("active")) button.classList.add("aktív"); else button.classList.remove("aktív" ); for(i változó = 0; i< buttons.length; i++) { button.addEventListener("click", toolbarButtonHandler); }
Nagy! Nemcsak mindent leegyszerűsítettünk egyetlen, többször használt funkcióra, hanem a kódunkat is olvashatóbbá tettük egy felesleges generátor funkció eltávolításával.

Azonban még mindig tehetünk jobbat.

Tegyük fel, hogy a kód végrehajtása után hozzáadtunk néhány gombot a laphoz. Ezután mindegyikhez eseménykezelőket is fel kell adnunk. És el kell tárolnunk egy linket ehhez a kezelőhöz és más helyekről származó hivatkozásokat. Nem tűnik túl csábítónak.

Talán van más megközelítés?

Kezdjük azzal, hogy megértsük, hogyan működnek az események, és hogyan haladnak a DOM-unkon.

Hogyan működik a legtöbb? Amikor a felhasználó rákattint egy elemre, egy esemény generálódik, amely értesíti erről az alkalmazást. Az egyes események útja három szakaszból áll:
  • Elfogási fázis
  • Az esemény a célelemen történik
  • Emelkedési fázis
  • Megjegyzés: nem minden esemény megy át az elfogási vagy buborékolási szakaszon, néhány esemény azonnal létrejön az elemen. Ez azonban inkább kivétel a szabály alól.

    Az esemény a dokumentumon kívül jön létre, majd a DOM-hierarchián keresztül egymás után a célelemhez kerül. Amint elérte a célját, az esemény ugyanúgy lekérésre kerül a DOM elemből.

    Íme a HTML sablonunk:

    • A gomb
    • B gomb
    • C gomb

    Amikor a felhasználó az A gombra kattint, az esemény a következőképpen halad:

    Indul
    | #dokumentum
    | Elfogási fázis
    | HTML
    | TEST
    | UL
    | LI#li_1
    | A gomb< - Событие возникает для целевого элемента
    | Emelkedési fázis
    | LI#li_1
    | UL
    | TEST
    | HTML
    v #dokumentum

    Figyeljük meg, hogy nyomon tudjuk követni azt az utat, amelyen egy esemény eléri célelemét. Esetünkben minden egyes gombnyomásnál biztosak lehetünk abban, hogy az esemény vissza fog buborékolni, áthaladva a szülőjén - az ul elemen. Használhatjuk ezt és megvalósíthatjuk a popup eseményeket.

    Buborékesemények A buborékesemények azok az események, amelyek egy szülőelemhez kapcsolódnak, de csak akkor hajtódnak végre, ha eleget tesznek valamilyen feltételnek.

    Vegyük konkrét példaként eszköztárunkat:

    Ul class="eszköztár">

  • Ceruza
  • Toll
  • radír

  • Most, hogy tudjuk, hogy a gombra bármely kattintás megjelenik az ul.toolbar elemen keresztül, csatoljuk hozzá az eseménykezelőnket. Szerencsére nálunk már megvan:

    Var eszköztár = document.querySelector(.toolbar"); toolbar.addEventListener("click", function(e) ( var gomb = e.target; if(!button.classList.contains("active")) button.classList.add("aktív"); else button.classList. remove("aktív" ));
    Sokkal tisztább kódunk van, és még a ciklusoktól is megszabadultunk! Ne feledje azonban, hogy az e.currentTarget helyére e.target került. Az ok abban rejlik, hogy az eseményeket más szinten dolgozzuk fel.

    Az e.target az esemény tényleges célpontja, ahol átjut a DOM-on, és ahonnan felfelé buborékol.
    e.currentTarget – az eseményt kezelő aktuális elem. Esetünkben ez az ul.toolbar.

    Továbbfejlesztett felugró események Jelenleg az ul.toolbar segítségével minden egyes elemre történő kattintást kezelünk, de az érvényesítési feltételünk túl egyszerű. Mi történne, ha bonyolultabb DOM-mal rendelkeznénk, amely olyan ikonokat és elemeket tartalmazna, amelyekre nem kattintásra készültek?

    • Ceruza
    • Toll
    • radír

    Hoppá! Most, amikor a li.separatorra vagy ikonra kattintunk, hozzáadjuk az .active osztályt. Ez legalábbis nem jó. Szükségünk van egy módra az események szűrésére, hogy a szükséges elemre reagáljunk.

    Ehhez hozzunk létre egy kis segítő függvényt:

    Var delegate = function(criteria, listener) ( return function(e) ( var el = e.target; do ( if (!criteria(el)) contense; e.delegateTarget = el; listener.apply(this, arguments); return; ) while((el = el.parentNode));
    Az asszisztensünk két dolgot csinál. Először minden elemet és azok szüleit iterálja, és ellenőrzi, hogy megfelelnek-e a feltételparaméterben megadott feltételnek. Ha az elem megfelel, a helper hozzáad egy delegateTarget nevű mezőt az eseményobjektumhoz, amely a feltételeinket kielégítő elemet tárolja. Aztán felhívja a kezelőt. Ennek megfelelően, ha egyetlen elem sem felel meg a feltételnek, akkor nem lesz kezelő sem.

    Így használhatjuk:

    Var eszköztár = document.querySelector(.toolbar"); var buttonsFilter = function(elem) ( return elem.classList && elem.classList.contains("btn"); ); var buttonHandler = function(e) ( var gomb = e.delegateTarget; if(!button.classList.contains("aktív")) button.classList.add("aktív"); else button.classList.remove("aktív" ); toolbar.addEventListener("click", delegate(buttonsFilter, buttonHandler));
    Pont amit az orvos rendelt: egy eseménykezelő egy elemhez van csatlakoztatva, amely minden munkát elvégz. De ezt csak a szükséges elemekre teszi. És tökéletesen reagál az objektumok DOM-hoz való hozzáadására és eltávolítására.

    Összegzés Röviden áttekintettük a delegálási (pop-up) események végrehajtásának alapjait tiszta JavaScriptben. Ez azért jó, mert nem kell minden elemhez egy csomó kezelőt generálnunk és csatolnunk.

    Ha ebből szeretnék könyvtárat készíteni, vagy a kódot a fejlesztés során használni, akkor hozzátennék pár dolgot:

    Segítő funkció annak ellenőrzésére, hogy egy objektum egységesebb és funkcionálisabb formában megfelel-e a kritériumoknak. Mint:

    Var kritériumok = ( isElement: function(e) ( HTMLElement e példánya; ), hasClass: function(cls) ( return function(e) ( return kritérium.isElement(e) && e.classList.contains(cls); ) ) //További kritériumok);
    Az asszisztens részleges használata is hasznos lenne:

    Var partialDelgate = function(kritériumok) ( return function(handler) ( return delgate(criteria, handler); ) );
    Eredeti cikk: A delegált JavaScript-események értelmezése
    (A fordítótól: az első, ítélje meg szigorúan.)

    Boldog kódolást!

    Ebben a leckében megismerkedünk az eseménybuborékolás fogalmával, és azt is megnézzük, hogyan lehet megszakítani. Ezenkívül megtudjuk, hogy az esemény milyen további szakaszokon (fázisokon) megy keresztül, mielőtt elkezdődik.

    Eseménybuborék

    Ha valamilyen elemnél bekövetkezik egy esemény, az elkezd „felbukkanni”, azaz. előfordul szülőnél, majd nagyszülőnél stb.

    Ebből következik, hogy valamely elem által generált esemény elfogható a szülő, nagyszülő stb. kezelője segítségével.

    Egy esemény (buborék) kialakulását a következő példával mutatjuk be:

    Cím

    Néhány nagyon fontos szöveg

    Fejezet

    Némi szöveg

    A szöveg többi része

    Írjunk egy kis szkriptet, amivel az összes oldalelemhez, illetve a dokumentum- és ablakobjektumokhoz is hozzáadunk egy "click" eseménykezelőt.

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

    Hozzunk létre egy HTML oldalt, és illesszük be a fenti HTML kódot. Beírt forgatókönyv JavaScript, illessze be a záró body címke elé. Ezután nyissa meg az újonnan létrehozott oldalt egy webböngészőben, nyomja meg az F12 billentyűt, és lépjen a konzolra. Most kattintsunk a bal gombbal az erős elemhez tartozó területen, és nézzük meg, hogyan ugrik fel az esemény.

    Hogyan szakítsuk meg az események bugyborékolását

    Egy esemény (buborék) felemelkedése megszakítható. Ebben az esetben ez az esemény nem aktiválódik magasabb (szülő) elemek esetén. Az esemény (buborék) terjedésének leállítására tervezett metódust stopPropagation()-nak nevezik.

    Például változtassuk meg a fenti példánkat, hogy az esemény ne buborékoljon a törzs felett: document.addEventListener("DOMContentLoaded", function() ( var allElements = document.getElementsByTagName("*"); for (var i=0 i

    Kétségtelen, hogy a burkolat nagyon kényelmes és építészetileg átlátható. Ne hagyja abba, hacsak nem feltétlenül szükséges.

    A kezelőt hívó elem lekérése

    Az eseménykezelőt hívó DOM elem (objektum) beszerzéséhez a this kulcsszót kell használni. Ez a kulcsszó (this) csak akkor érhető el a kezelőben, ha JavaScript használatával feliratkozik az eseményre.

    Például jelenítsük meg a konzolban az eseménykezelőt hívó elem azonosítóját:

    Var myP = document.getElementById("myP"); myP.addEventListener("click",function())( //lekéri az eseménykezelőt hívó DOM elemet - ez //kérje le az azonosítóját és adja ki a konzolba console.log(this.id); ));

    Az aktuális elem lekéréséhez használhatja a currentTarget tulajdonságot (event.currentTarget) is.

    Az esemény szakaszai (fázisai).

    Mielőtt egy esemény elkezdene megjelenni (az emelkedési szakasz), először további 2 szakaszon megy keresztül:

    • Az 1. szakasz az eseményt generáló elembe való belemerülés szakasza. Azok. ebben a szakaszban van egy mozgás fentről lefelé, azaz. az ablak objektumtól az elemig. Is ezt a szakaszt interception szakasznak is nevezik.
    • A 2. szakasz a cél elérésének szakasza, azaz. elem (objektum), amely az eseményt generálta.

    Figyelembe véve az összes szakaszt, amelyen egy esemény átmegy, a következő képet kapjuk:

    Módosítsuk a fenti példaszkriptet az alábbiak szerint:

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

    Az addEventListener és removeEventListener metódusok harmadik paramétere határozza meg, hogy az esemény melyik szakaszában kerül rögzítésre. Ha ez a paraméter igaz, akkor az eseményt az esemény bemerülési (elfogási) szakaszában fogja el. És ha a paraméter false , akkor az eseményt a rendszer elfogja a buborékolási szakaszban. Egy esemény kezeléséhez magán a célon használhatja az addEventListener metódust false vagy true értékkel.

    Figyelem: az immerziós (elfogó) szakaszban az eseményeket csak az addEventListener() metódussal hozzáadott kezelők tudják elfogni. A más módszerekkel (HTML attribútum vagy JavaScript segítségével az on[event] tulajdonság használatával) hozzáadott kezelők csak a buborékolási szakaszban tudják elfogni az eseményeket.

    Az eseményt generáló elem lekérése

    A célelem megszerzése érdekében, pl. az eseményt generáló elemnek a céltulajdonságot (event.target) kell használnia.

    Tekintsük a fenti példát, amelyben a script elem tartalmát a következőre változtatjuk:

    Document.addEventListener("DOMContentLoaded", function() ( var elementBody = document.body; elementBody.addEventListener("click",function())( console.log(this.tagName + " - a kezelőt hívó elem") ; console .log(event.currentTarget.tagName + " - a kezelőt hívó elem" console.log(event.target.tagName + " - az eseményt létrehozó elem" ),false);

    Mutassuk meg példánkat úgy, hogy az erős elemhez tartozó területen bal egérgombbal kattintunk: