,
Jsou zde stejní psovodi jako dříve, ale tentokrát - ve fázi ponoření. Chcete-li vidět zachycení v akci, klikněte na prvek v něm
Ovladače budou pracovat v pořadí shora dolů: FORM → DIV → P.
JS kód je takto:
varelems = document.querySelectorAll("form,div,p"); // na každý prvek pověsíme handler ve fázi zachycení pro (var i = 0; i< elems.length; i++) {
elems[i].addEventListener("click", highlightThis, true);
}
Nikdo vás neobtěžuje přidělovat handlery pro obě fáze, jako je tento:
varelems = document.querySelectorAll("form,div,p"); for (var i = 0; i< elems.length; i++) {
elems[i].addEventListener("click", highlightThis, true);
elems[i].addEventListener("click", highlightThis, false);
}
Klikněte na vnitřní prvek
Chcete-li zobrazit pořadí, ve kterém událost prochází: Mělo by být FORM → DIV → P → P → DIV → FORM. Všimněte si, že prvek
Zúčastní se obou etap.
Výsledek
Když dojde k události, prvek, na kterém k události došlo, je označen jako event.target.
Událost se nejprve přesune dolů z kořenového adresáře dokumentu do event.target , přičemž během cesty zavolá obslužné programy dodávané prostřednictvím addEventListener(…., true).
Událost se přesune z event.target až na začátek dokumentu, zatímco volá handlery dodané přes addEventListener(…., false).
Každý handler bude mít přístup k vlastnostem události:
event.target je nejhlubší prvek, na kterém se událost skutečně stala.
event.currentTarget (=toto) je prvek, na kterém je tento moment pracoval self-handler (ke kterému se událost „dostala“).
event.eventPhase – v jaké fázi se obsluha události spustila (ponor = 1, plovoucí = 3).
Bublinkování lze zastavit voláním metody event.stopPropagation(), ale to se nedoporučuje, protože událost můžete potřebovat pro neočekávané účely.
Nyní se podíváme na některé pokročilé věci při práci s objektem Event, konkrétně: probublávání a zachycování a také delegování událostí.
Událost bublá
Představte si, že máte několik vnořených bloků:
Když kliknete na nejvnitřnější blok, událost při kliknutí vyskytuje se nejprve v něm a pak se spouští v jeho nadřazeném prvku, v nadřazeném prvku jeho rodiče atd., dokud nedosáhne této značky tělo a na značku html (pak do dokument a předtím okno ).
A to je logické, protože kliknutím na vnitřní blok současně kliknete na všechny vnější.
Podívejme se na to v následujícím příkladu: máme 3 bloky, ke každému z nich je připojena událost onclick:
Klikněte na nejvnitřnější červený blok - a uvidíte, jak bude fungovat nejprve kliknutí červeného bloku, poté modrého a poté zeleného:
Toto chování se nazývá povrchová úprava události - analogicky se vzestupem vzduchové bubliny ze dna. Stejně jako bublina se zdá, že naše kliknutí na vnitřní prvek vyplave nahoru a pokaždé se spustí na vyšších blocích.
událost.cíl
Řekněme, že máme dva prvky: div a odstavec p, který leží uvnitř tohoto divu. Pojďme onlick svázat do diva:
Když klikneme na tento div, můžeme přejít na odstavec, nebo můžeme přejít na místo, kde tento odstavec neexistuje.
Jak to může být - podívejte se na následující příklad: zelená je náš div a modrá je náš odstavec:
Pokud kliknete na zelenou část, klikneme na div, a pokud kliknete na modrou část, dojde ke kliknutí nejprve na odstavec a poté na div. Ale protože onclick je připojen konkrétně k div, obecně si nemusíme všimnout přítomnosti odstavce.
Někdy bychom však rádi věděli, zda ke kliknutí došlo přímo na div nebo na jeho následný odstavec. K tomu nám pomůže objekt Event a jeho vlastnost. událost.cíl - ukládá přesně ten prvek, ve kterém došlo ke kliknutí.
V následujícím příkladu máme div , uvnitř leží p a uvnitř - rozpětí .
Navažme událost onclick na nejvyšší prvek (div) a klikneme na různé prvky: div, p, span. Používáním událost.cíl získejte nejspodnější prvek, kde k události došlo, a zobrazte jeho název pomocí tagName .
Kliknete-li např. na rozpětí, událost zachytí náš div (koneckonců je k němu připojen onclick), ale v událost.cíl bude přesně lhát rozpětí :
Klikněte na různé bloky - uvidíte výsledek:
Zastavení stoupání
Takže už víte, že všechny události vyskakují až nahoru (až html tag a pak do dokumentu a pak do okna). Někdy je potřeba toto stoupání zastavit. To lze provést libovolným prvkem, přes který událost vyskočí. Chcete-li to provést, v kódu prvku zavolejte metodu event.stopPropagation() .
V následujícím příkladu bude kliknutí na červený blok fungovat samo, pak na modrý blok a je to - modrý blok zastaví další stoupání a zelený blok nebude nijak reagovat:
Klikněte na červený blok - uvidíte výsledek:
Ponoření
Kromě bublání akcí existuje také potápět se (podle vědeckých etapa odposlechu ). To znamená, že událost jde nejprve shora dolů (záchytná fáze), dosáhne našeho prvku (cílová fáze) a teprve poté se začne vznášet (etapa bublání).
Obsluhu události můžete zavěsit s ohledem na fázi zachycení pouze pomocí addEventListener . K tomu má třetí parametr: pokud je to pravda, událost se spustí ve fázi zachycení, a pokud je nepravda, ve fázi bublání (toto je ve výchozím nastavení):
Vargreen = document.getElementById("zelená"); green.addEventListener("click", func, true); func(událost) ( )
Pomocí vlastnosti lze určit fázi, ve které k události došlo event.eventPhase . Může nabývat následujících hodnot: 1 - záchytný stupeň, 2 - cílový stupeň, 3 - stupeň stoupání.
Úvod do delegace
Představte si situaci: nechte nás ul S několika li . Ke každému li je připojena následující událost: po kliknutí na li se na jeho konec přidá „!“.
Pojďme implementovat výše uvedené:
odstavec 1
bod 2
bod 3
bod 4
bod 5
var li = document.querySelectorAll("#ul li"); //Ve smyčce zavěsíme funkci addSign na každé li: for (var i = 0; i
Klikněte na li - uvidíte, jak se na jejich konec přidá "!":
odstavec 1
bod 2
bod 3
bod 4
bod 5
Nechť nyní máme také tlačítko, kliknutím na které se přidá nové na konec ul li s textem "položka". Čeká nás překvapení: přiložená akce nebude fungovat za nové li! Přesvědčte se o tom:
odstavec 1
bod 2
bod 3
bod 4
bod 5
Přidejte li
Klikněte na tlačítko pro přidání li a poté na toto nové li – nebude reagovat:
odstavec 1
bod 2
bod 3
bod 4
bod 5
Přidejte li
Chcete-li problém vyřešit, v době vytváření nového li na něj zavěste funkci addSign přes addEventListener. Pojďme to implementovat:
odstavec 1
bod 2
bod 3
bod 4
bod 5
Přidejte li var li = document.querySelectorAll("#ul li"); for (var i = 0; i
odstavec 1
bod 2
bod 3
bod 4
bod 5
Přidejte li
Existuje druhý způsob, jak problém obejít - delegování události. Pojďme to analyzovat.
Delegace akce
Podstata delegování je následující: nezavěsíme událost na každého li, ale na jejich rodiče - na ul .
Zároveň by měl být zachován výkon našeho skriptu: stejně jako dříve se při kliknutí na li na jeho konec přidá „!“. Pouze událost v nové verzi bude zavěšena na ul:
var ul = document.getElementById("ul"); //Zavěste událost na ul: ul.addEventListener("click", addSign); funkce addSign() ( )
Jak to uděláme: protože událost je zavěšena na ul, uvnitř funkce můžeme zachytit li událost.cíl . Dovolte mi připomenout, co je event.target - to je přesně tag, ve kterém došlo ke kliknutí, v našem případě tomu tak je li .
Zde je tedy řešení našeho problému prostřednictvím delegování:
odstavec 1
bod 2
bod 3
bod 4
bod 5
Výsledek spuštění kódu:
odstavec 1
bod 2
bod 3
bod 4
bod 5
V tomto případě bude naše řešení fungovat automaticky i pro nové li , protože událost není zavěšena na li, ale na ul:
odstavec 1
bod 2
bod 3
bod 4
bod 5
Přidejte li var ul = document.getElementById("ul"); ul.addEventListener("click", addSign); function addSign() ( event.target.innerHTML = event.target.innerHTML + "!"; ) //Implementace tlačítka pro přidání nového li: var button = document.getElementById("button"); button.addEventListener("klikni", addLi); funkce addLi() ( var li = document.createElement("li"); li.innerHTML = "nové li"; ul.appendChild(li); )
Klikněte na tlačítko pro přidání li a poté na toto nové li - bude reagovat:
odstavec 1
bod 2
bod 3
bod 4
bod 5
Přidejte li
Náš kód funguje, ale ne bez chyb. Pojďme si tyto nedostatky rozebrat a napsat univerzálnější řešení.
Delegování obecné události
Nevýhoda našeho kódu se projeví, když jsou uvnitř li nějaké vnořené značky. V našem případě budiž tagy i :
V tomto případě stiskněte i bude mít za následek přidání vykřičníku konec značky i , nikoli štítek li , jak bychom chtěli (pokud kliknete na li mimo kurzívu, pak bude vše v pořádku):
odstavec kurzíva 1
odstavec kurzíva 2
odstavec kurzíva 3
odstavec kurzíva 4
odstavec kurzíva 5
var ul = document.getElementById("ul"); ul.addEventListener("click", addSign); funkce addSign() ( event.target.innerHTML = event.target.innerHTML + "!"; )
Klikněte na kurzívu - uvidíte, jak "!" bude přidáno na jeho konec (stisknutí mimo kurzívu bude fungovat dobře):
Problém je vyřešen následovně (popsaná metoda není jediná, ale nejjednodušší): pomocí nejbližší metody najdeme nejbližší li, která je rodičem event.target takto: event.target.closest("li") .
Jak to funguje: pokud bylo kliknutí zapnuto i , pak dovnitř událost.cíl to lžu a v event.target.closest("li") - naše li, pro kterou by událost měla vypálit.
Pokud bylo kliknutí na li , pak dovnitř událost.cíl a v event.target.closest("li") naše li bude lhát.
Pojďme zkontrolovat:
odstavec kurzíva 1
odstavec kurzíva 2
odstavec kurzíva 3
odstavec kurzíva 4
odstavec kurzíva 5
var ul = document.getElementById("ul"); ul.addEventListener("click", function(event) ( var li = event.target.closest("li"); if (li) ( //zkontrolujte, zda vůbec neexistuje žádný nadřazený li li.innerHTML = li.innerHTML + "!";)));
Výsledek spuštění kódu:
Bez ohledu na to, jak hluboké je vnoření: tag i může být ve značce b a ten ve značce rozpětí a teprve potom dovnitř li - to je jedno: stavba event.target.closest("li") najde rodiče z libovolné úrovně vnoření.
Když dojde k události, obslužné rutiny vystřelí nejprve na samotný vnořený prvek, poté na jeho nadřazený prvek, poté nad ním a tak dále v řetězci vnoření.
Například existují 3 vnořené prvky FORM > DIV > P , s obslužnou rutinou na každém:
Kód:
Bublinkování zajišťuje kliknutí na vnitřní straně
Nejprve zavolá obsluhu onclick (pokud existuje).
Pokud tedy kliknete na P ve výše uvedeném příkladu, zobrazí se upozornění postupně: p → div → formulář.
Tento proces se nazývá bublání, protože události probublávají z vnitřního elementu nahoru přes rodiče, podobně jako vzduchová bublina plave ve vodě.
událost.cíl
Na jakémkoli prvku, který událost zachytíme, vždy můžete zjistit, kde přesně se stala. Nejhlubší prvek, který událost spustí, se nazývá prvek „target“ nebo „source“ a je dostupný jako event.target.
Rozdíly od tohoto (=event.currentTarget):
event.target je zdrojový prvek, na kterém událost nastala, během procesu probublávání se nemění.
toto je aktuální prvek, kterého bublání dosáhlo, handler na něm právě provádí.
Pokud například existuje pouze jeden obslužný program form.onclick, „zachytí“ všechna kliknutí uvnitř formuláře. Všude, kde uvnitř dojde ke kliknutí - vyskočí na prvek
Div ( margin-bottom: 10px; )
Nyní trochu JavaScriptu - zde implementujeme velmi jednoduchou kontrolu uvnitř obslužné rutiny události onsubmit (událost submit se spustí na formuláři při jeho odeslání), která testuje, zda jsou textová pole prázdná. Pokud ano, zavoláme funkci preventDefault() na objektu události – která zastaví odesílání formuláře – a poté zobrazíme chybovou zprávu v odstavci pod formulářem, abychom uživateli řekli, co je špatně:
Const form = document.querySelector("form"); const fname = document.getElementById("fname"); const lname = document.getElementById("lname"); const para = document.querySelector("p"); form.onsubmit = function(e) ( if (fname.value === "" || lname.value === "") ( e.preventDefault(); para.textContent = "Musíte vyplnit oba názvy! ";))
Je zřejmé, že je to dost slabé ověření formuláře - nezabrání uživateli ověřovat formulář například mezerami nebo čísly zadanými do polí - ale je to v pořádku například pro účely. Výstup je následující:
Událost bublá a zachycuje
Poslední téma, které je zde třeba probrat, je něco, s čím se často nesetkáte, ale pokud mu nerozumíte, může to být opravdu nepříjemné. Probublávání událostí a zachycení jsou dva mechanismy, které popisují, co se stane, když jsou na jednom prvku aktivovány dva handlery stejného typu události. Podívejme se na příklad, abychom si to usnadnili – otevřete ukázku show-video-box.html na nové kartě (a na jiné kartě.) Níže je také k dispozici živě:
Příklad skrytého videa
Zobrazit příklad video boxu
Zobrazit video
místo toho odkaz na video.
Toto je docela jednoduchý příklad, který ukazuje a skrývá a) je obecný kontejner pro obsah toku. Nemá žádný vliv na obsah nebo rozvržení, dokud nebude stylizován pomocí CSS.">
s a) vloží do dokumentu přehrávač médií, který podporuje přehrávání videa. Můžeš použít
také pro zvukový obsah, ale prvek může poskytnout vhodnější uživatelský zážitek."> prvek uvnitř:
Zobrazit video
Váš prohlížeč nepodporuje HTML5 video. Zde je odkaz na video.
Poznámka : Proč se obtěžovat jak zachycením, tak probubláváním? No, za starých špatných časů, kdy byly prohlížeče mnohem méně vzájemně kompatibilní než nyní, Netscape používal pouze zachycování událostí a Internet Explorer používal pouze probublávání událostí. Když se W3C rozhodlo pokusit se standardizovat chování a dosáhnout konsensu, skončilo u tohoto systému, který zahrnoval obojí, což je ten, který implementují moderní prohlížeče.
Poznámka : Jak bylo zmíněno výše, ve výchozím nastavení jsou všechny obslužné rutiny událostí registrovány ve fázi probublávání, což dává většinou větší smysl. Pokud místo toho opravdu chcete zaregistrovat událost ve fázi zachycování, můžete tak učinit registrací svého handleru pomocí addEventListener() a nastavením volitelné třetí vlastnosti na true .
delegování akce
Probublávání nám také umožňuje využít delegování akce - tento koncept se opírá o skutečnost, že pokud chcete, aby se po kliknutí na některý z velkého počtu podřízených prvků spustil nějaký kód, můžete nastavit posluchače událostí na jejich rodiče a nechat události, které se na nich dějí, probublávat k jejich nadřazenému prvku místo toho, abyste museli nastavovat posluchače událostí na každé dítě individuálně. Pamatujete si dříve, že jsme řekli, že bublání zahrnuje nejprve kontrolu prvku, na kterém je událost vyvolána, pro obsluhu události, poté přesun k nadřazenému prvku atd.?
Dobrým příkladem je řada položek seznamu – pokud chcete, aby se u každé z nich po kliknutí zobrazila zpráva, můžete nastavit posluchač události kliknutí na nadřazeném
a události budou probublávat z položek seznamu do .
Tento koncept je dále vysvětlen na blogu Davida Walshe s několika příklady – viz Jak funguje delegování událostí JavaScriptu .
Závěr
Nyní byste měli vědět vše, co potřebujete vědět o webových událostech v této rané fázi. Jak bylo uvedeno výše, události ve skutečnosti nejsou součástí jádra JavaScriptu – jsou definovány ve webových rozhraních API prohlížeče.