Úvod do pop-up událostí. Pokročilá práce s objektem Event v JavaScriptu Zrušení probublávání událostí js

V této lekci se seznámíme s konceptem probublávání událostí a také se podíváme na to, jak jej lze přerušit. Navíc zjistíme, jakými dalšími fázemi (fázemi) událost prochází, než začne vznikat.

Bublina události

Pokud u nějakého prvku nastane událost, začne „vyskakovat“, tzn. vyskytuje se u rodiče, pak u prarodiče atd.

Z toho vyplývá, že událost vygenerovaná nějakým prvkem může být zachycena pomocí handleru na jeho rodiči, prarodičovi atd.

Vznik události (bubliny) si ukážeme na následujícím příkladu:

Nadpis

Nějaký velmi důležitý text

Kapitola

Nějaký text

Zbytek textu

Napišme si malý skript, pomocí kterého přidáme obslužnou rutinu události "kliknutí" pro všechny prvky stránky, stejně jako pro objekty dokumentu a okna.

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

Vytvořme HTML stránku a vložíme do ní výše uvedený HTML kód. Skript napsaný v JavaScript, vložte před koncovou značku těla. Poté otevřete nově vytvořenou stránku ve webovém prohlížeči, stiskněte klávesu F12 a přejděte do konzole. Nyní klikneme levým tlačítkem myši do oblasti patřící silnému prvku a uvidíme, jak se událost objeví.

Jak přerušit bublání událostí

Nástup události (bubliny) lze přerušit. V tomto případě se tato událost nespustí pro vyšší (nadřazené) prvky. Metoda, která je navržena k zastavení šíření události (bubliny), se nazývá stopPropagation() .

Změňme například náš výše uvedený příklad tak, aby událost nevybuchla nad tělem: document.addEventListener("DOMContentLoaded", function() ( var allElements = document.getElementsByTagName("*"); for (var i=0 i

Povrchová úprava je nepochybně velmi pohodlná a architektonicky transparentní. Nezastavujte to, pokud to není nezbytně nutné.

Získání prvku, který volal handler

Chcete-li získat prvek DOM (objekt), který volal obslužnou rutinu události, musíte použít klíč slovo toto. Dáno klíčové slovo(toto) je v obslužné rutině k dispozici pouze v případě, že se přihlásíte k odběru události pomocí JavaScriptu.

Zobrazme například v konzole id prvku, který volal obslužnou rutinu události:

Var myP = document.getElementById("myP"); myP.addEventListener("click",function())( //získání prvku DOM, který volal obslužnou rutinu události - toto //získáte jeho id a odešlete jej do konzole console.log(this.id); ));

K získání aktuálního prvku můžete také použít vlastnost currentTarget (event.currentTarget).

Etapy (fáze) děje

Než se událost začne vynořovat (stupeň výstupu), projde nejprve dvěma dalšími fázemi:

  • Fáze 1 je fáze ponoření do prvku, který generoval událost. Tito. v této fázi dochází k pohybu shora dolů, tzn. z objekt okna k prvku. Tato fáze se také nazývá fáze zachycení.
  • Fáze 2 je fáze dosažení cíle, tzn. prvek (objekt), který událost vygeneroval.

Vezmeme-li v úvahu všechny fáze, kterými událost prochází, objeví se následující obrázek:

Upravme výše uvedený příklad skriptu následovně:

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

Třetí parametr metod addEventListener a removeEventListener určuje fázi, ve které bude událost zachycena. Li tento parametr je nastavena na hodnotu true , událost bude zachycena ve fázi ponoření (zachycení) události. A pokud je parametr false , událost bude zachycena ve fázi bublání. Chcete-li zpracovat událost na samotném cíli, můžete použít metodu addEventListener jako u hodnota nepravda a s hodnotou true .

Upozornění: během fáze ponoření (zachycení) mohou být události zachyceny pouze handlery přidanými pomocí metody addEventListener(). Obslužné nástroje přidané pomocí jiných metod ( HTML atribut nebo prostřednictvím JavaScriptu pomocí vlastnosti on[event]) může zachytit události pouze ve fázi probublávání.

Získání prvku, který událost vygeneroval

Abychom získali cílový prvek, tzn. prvek, který událost vygeneroval, musí používat vlastnost target (event.target).

Zvažte výše uvedený příklad, ve kterém změníme obsah prvku skriptu na následující:

Document.addEventListener("DOMContentLoaded", function() ( var elementBody = document.body; elementBody.addEventListener("click",function())( console.log(this.tagName + " - prvek, který vyvolal obslužnou rutinu") ; console .log(event.currentTarget.tagName + " - prvek, který volal obslužnou rutinu"); console.log(event.target.tagName + " - prvek, který vygeneroval událost"); ),false); )) ;

Ukažme si náš příklad kliknutím levým tlačítkem myši na oblast patřící silnému prvku:

Všechno to začalo používáním JavaScriptu a tříd.

Nicméně mám problém. Chtěl jsem použít něco, co se nazývá Bubble Events, ale také jsem chtěl minimalizovat závislosti, které bych musel vložit. Nechtěl jsem se připojit jQuery knihovny pro "tento malý test", stačí použít vyskakovací události.

Podívejme se blíže na to, co jsou toastovací akce, jak fungují a pár způsobů, jak je realizovat.

Dobře, tak v čem je problém? Podívejme se na jednoduchý příklad:

Řekněme, že máme seznam tlačítek. Pokaždé, když na jednu z nich kliknu, měla by se stát „aktivní“. Po opětovném stisknutí by se tlačítko mělo vrátit do původního stavu.

Začněme s HTML:

  • Tužka
  • Pero
  • guma

Mohl bych použít standardní obslužnou rutinu událostí JavaScriptu takto:

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"); }); }
Vypadá to dobře... Ale nebude to fungovat. Podle alespoň, ne tak, jak to očekáváme.

Uzávěry vítězí Pro ty, kteří znají trochu funkční JavaScript, je problém zřejmý.

Pro zbytek stručně vysvětlím - funkce handleru je uzamčena na proměnnou tlačítka. Toto je však jediná proměnná a při každé iteraci se přepíše.

V první iteraci se proměnná odkazuje na první tlačítko. V dalším - do druhého a tak dále. Ale když uživatel klikne na tlačítko, smyčka již skončila a proměnná tlačítka odkazuje na poslední tlačítko, které vždy zavolá obsluhu události. Porucha.

Potřebujeme samostatný kontext pro každou funkci:

Tlačítka Var = document.querySelectorAll(".tlačítko panelu nástrojů"); 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])); }
Mnohem lepší! A hlavně to funguje správně. Vytvořili jsme funkci createToolbarButtonHandle, která vrací obsluhu události. Ke každému tlačítku pak připevníme vlastní handler.

Tak co je za problém? Vypadá to dobře a funguje. Navzdory tomu stále můžeme náš kód vylepšit.

Nejprve vytvoříme příliš mnoho ovladačů. Pro každé tlačítko uvnitř .toolbaru vytvoříme funkci a svážeme ji jako obsluhu události. U tří tlačítek je využití paměti zanedbatelné.

Ale pokud máme něco takového:

  • Foo
  • Bar
  • // ...dalších 997 prvků...
  • baz

pak počítač samozřejmě z přetečení nevybuchne. Naše využití paměti však zdaleka není ideální. Alokujeme toho obrovské množství, i když se bez toho obejdeme. Znovu přepišme náš kód, abychom mohli stejnou funkci použít vícekrát.

Namísto odkazování na proměnnou tlačítka pro sledování toho, na které tlačítko jsme klikli, můžeme použít objekt události, který je předán jako první argument každé obsluze události.

Objekt Event obsahuje některá data o události. V našem případě nás zajímá pole currentTarget. Z něj získáme odkaz na prvek, na který jsme klikli:

Var toolbarButtonHandler = function(e) ( var button = e.currentTarget; if(!button.classList.contains("active")) button.classList.add("active"); jinak button.classList.remove("active" );); for(var i = 0; i< buttons.length; i++) { button.addEventListener("click", toolbarButtonHandler); }
Skvělý! Nejen, že jsme vše zjednodušili na jedinou funkci, která se používá vícekrát, ale také jsme učinili náš kód čitelnějším tím, že jsme odstranili nepotřebnou funkci generátoru.

Stále však můžeme být lepší.

Řekněme, že jsme do listu přidali některá tlačítka po provedení našeho kódu. Pak bychom také museli přidat obslužné rutiny událostí pro každou z nich. A museli bychom uložit odkaz na tento handler a odkazy z jiných míst. Nevypadá příliš lákavě.

Možná existuje jiný přístup?

Začněme tím, že pochopíme, jak události fungují a jak se pohybují po našem DOM.

Jak většina z nich funguje? Když uživatel klikne na prvek, vygeneruje se událost, která o tom informuje aplikaci. Cesta každé události probíhá ve třech fázích:
  • Fáze odposlechu
  • U cílového prvku dojde k události
  • Fáze stoupání
  • Poznámka: ne všechny události procházejí fází zachycení nebo bublání, některé jsou vytvořeny přímo na prvku. To je však spíše výjimka z pravidla.

    Událost se vytvoří mimo dokument a poté se postupně přesune přes hierarchii DOM do cílového prvku. Jakmile dosáhne svého cíle, je událost načtena z prvku DOM stejným způsobem.

    Zde je naše HTML šablona:

    • Tlačítko A
    • Tlačítko B
    • Tlačítko C

    Když uživatel klikne na tlačítko A, událost proběhne takto:

    Start
    | #dokument
    | Fáze odposlechu
    | HTML
    | TĚLO
    | UL
    | LI#li_1
    | Tlačítko A< - Событие возникает для целевого элемента
    | Fáze stoupání
    | LI#li_1
    | UL
    | TĚLO
    | HTML
    v #dokument

    Všimněte si, že můžeme sledovat cestu, kterou událost urazí, aby dosáhla svého cílového prvku. V našem případě si pro každé stisknuté tlačítko můžeme být jisti, že událost znovu vybuchne a projde svým rodičem - prvkem ul. Můžeme toho využít a implementovat vyskakovací události.

    Události bublin Události bublin jsou ty události, které jsou připojeny k nadřazenému prvku, ale jsou provedeny pouze tehdy, pokud splňují nějakou podmínku.

    Vezměme si náš panel nástrojů jako konkrétní příklad:

    Ul class="toolbar">

  • Tužka
  • Pero
  • guma

  • Nyní, když víme, že každé kliknutí na tlačítko se objeví přes prvek ul.toolbar, připojme k němu naši obsluhu události. Naštěstí už to máme:

    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. remove("aktivní"); ));
    Nyní máme mnohem čistší kód a dokonce jsme se zbavili smyček! Všimněte si však, že jsme nahradili e.currentTarget za e.target . Důvod spočívá v tom, že zpracováváme události na jiné úrovni.

    e.target je skutečný cíl události, kde si razí cestu přes DOM a odkud pak vybuchne.
    e.currentTarget - aktuální prvek, který zpracovává událost. V našem případě je to ul.toolbar.

    Vylepšené bublinové události tento moment Každé kliknutí na každý prvek, který se objeví, zpracováváme přes ul.toolbar , ale naše podmínka ověření je příliš jednoduchá. Co by se stalo, kdybychom měli složitější DOM, který by obsahoval ikony a prvky, na které se neklikalo?

    • Tužka
    • Pero
    • guma

    Jejda! Nyní, když klikneme na li.separator nebo ikonu, přidáme k ní třídu .active. Přinejmenším to není dobré. Potřebujeme způsob, jak filtrovat události, abychom reagovali na prvek, který potřebujeme.

    Vytvořme si k tomu malou pomocnou funkci:

    Var delegát = function(kritéria, posluchač) ( return function(e) ( var el = e.target; do ( if (!criteria(el)) pokračovat; e.delegateTarget = el; listener.apply(toto, argumenty); return; ) while((el = el.parentNode)); ); );
    Náš asistent dělá dvě věci. Nejprve iteruje každý prvek a jeho rodiče a zkontroluje, zda splňují podmínku zadanou v parametru kritéria. Pokud prvek vyhovuje, pomocník přidá do objektu události pole nazvané delegátTarget, ve kterém je uložen prvek, který splňuje naše podmínky. A pak zavolá psovoda. Pokud tedy žádný prvek nesplňuje podmínku, nebude volána žádná obsluha.

    Můžeme to použít takto:

    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("kliknutí", delegát(buttonsFilter, buttonHandler));
    Přesně to, co doktor nařídil: jedna obsluha události připojená k jednomu prvku, který dělá veškerou práci. Ale dělá to jen pro prvky, které potřebujeme. A perfektně reaguje na přidávání a odebírání objektů z DOM.

    Shrnutí Stručně jsme si zopakovali základy implementace delegování (zpracování vyskakovacích) událostí na čistý JavaScript. To je dobré, protože nepotřebujeme generovat a připojovat spoustu handlerů pro každý prvek.

    Pokud bych z toho chtěl vytvořit knihovnu nebo použít kód ve vývoji, přidal bych pár věcí:

    Pomocná funkce pro kontrolu, zda objekt splňuje kritéria v jednotnější a funkčnější podobě. Jako:

    Var kritéria = ( isElement: function(e) ( return e instanceof HTMLElement; ), hasClass: function(cls) ( return function(e) ( return kritéria.isElement(e) && e.classList.contains(cls); ) ) //Další kritéria);
    Částečné využití asistenta by bylo také užitečné:

    Var parcialDelgate = function(kriteria) ( return function(handler) ( return delgate(criteria, handler); ) );
    Původní článek: Understanding Delegated JavaScript Events
    (Od překladatele: můj první, posuzujte přísně.)

    Šťastné kódování!

    Události jsou akce nebo události, ke kterým dochází v systému, který programujete a o kterých vám systém říká, abyste na ně mohli v případě potřeby nějakým způsobem reagovat. Pokud například uživatel klepne na tlačítko na webové stránce, můžete na tuto akci reagovat zobrazením informačního pole. V tomto článku diskutujeme o některých důležitých konceptech souvisejících s událostmi a podíváme se, jak fungují v prohlížečích. Nebude to vyčerpávající studie, jen co potřebuješ vědět v této fázi.

    Předpoklady: Objektivní:
    Základní počítačová gramotnost, základní znalost HTML a CSS, JavaScript první kroky.
    Pochopit základní teorii událostí, jak fungují v prohlížečích a jak se události mohou lišit v různých programovacích prostředích.
    Řada šťastných událostí

    Jak již bylo zmíněno výše, události jsou akce nebo události, které se stanou v systému, který programujete – systém produkuje (nebo „vystřelí“) signál určitého druhu, když nastane událost, a také poskytuje mechanismus, pomocí kterého lze nějaký druh akce provést. automaticky převzaty (to znamená, že nějaký kód běží), když dojde k události. Například na letišti, když je dráha volná pro vzlet letadla, je pilotovi předán signál a v důsledku toho začnou pilotovat letadlo.

    V případě webu se události spouštějí uvnitř okna prohlížeče a mají tendenci být připojeny ke konkrétní položce, která se v něm nachází – může to být jeden prvek, sada prvků, dokument HTML načtený na aktuální kartě nebo celé okno prohlížeče. Existuje mnoho různých typů událostí, které mohou nastat, například:

    • Uživatel klikne myší na určitý prvek nebo najede kurzorem na určitý prvek.
    • Uživatel stiskne klávesu na klávesnici.
    • Uživatel změní velikost nebo zavře okno prohlížeče.
    • Odesílá se formulář.
    • Video, které se přehrává, pozastavuje nebo dokončuje přehrávání.
    • Došlo k chybě.

    Z toho (a z pohledu na referenci událostí MDN) můžete usoudit, že existuje mnoho událostí, na které lze reagovat.

    Každá dostupná událost má obslužnou rutinu události , což je blok kódu (obvykle funkce JavaScriptu, kterou jako programátor vytvoříte), který se spustí, když se událost spustí. Když je takový blok kódu definován, aby byl spuštěn v reakci na spuštění události, říkáme, že registrujeme obsluhu události . Všimněte si, že obslužné rutiny událostí se někdy nazývají posluchači událostí - pro naše účely jsou do značné míry zaměnitelné, ačkoli přísně vzato, spolupracují. Posluchač poslouchá, zda se událost děje, a handler je kód, který je spuštěn v reakci na událost.

    Poznámka: Webové události nejsou součástí základního jazyka JavaScript – jsou definovány jako součást rozhraní API zabudovaných v prohlížeči.

    Jednoduchý příklad

    Podívejme se na jednoduchý příklad, abychom vysvětlili, co zde máme na mysli. Události a obslužné nástroje událostí jste již viděli v mnoha příkladech v tomto kurzu, ale pojďme si to zrekapitulovat, abychom upevnili naše znalosti. V následujícím příkladu máme single , jehož stisknutím se pozadí změní na náhodnou barvu:

    Změnit barvu

    Tlačítko ( okraj: 10px );

    JavaScript vypadá takto:

    Const btn = document.querySelector("tlačítko"); function 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; )

    V tomto kódu ukládáme odkaz na tlačítko uvnitř konstanty nazvané btn pomocí funkce Document.querySelector(). Definujeme také funkci, která vrací náhodné číslo. Třetí částí kódu je obslužná rutina události. Konstanta btn ukazuje na prvek a tento typ objektu má řadu událostí, které se na něm mohou spustit, a proto jsou k dispozici obslužné rutiny událostí. Nasloucháme spuštění události click nastavením vlastnosti obslužné rutiny události onclick tak, aby se rovnala anonymní funkci obsahující kód, který generuje náhodnou barvu RGB a nastavuje jí stejnou barvu pozadí.

    Tento kód se spustí vždy, když se na prvku spustí událost click, tedy vždy, když na něj uživatel klikne.

    Příklad výstupu je následující:

    Nejsou to jen webové stránky

    Další věc, která v tomto bodě stojí za zmínku, je, že události nejsou jedinečné pro JavaScript – většina programovacích jazyků má nějaký model událostí a způsob, jakým model funguje, se často liší od způsobu JavaScriptu. Ve skutečnosti model událostí v JavaScriptu pro webové stránky se liší od modelu událostí pro JavaScript, protože se používá v jiných prostředích.

    Inline obslužné nástroje událostí – nepoužívejte je

    Ve svém kódu můžete také vidět vzor, ​​jako je tento:

    Stiskněte mě funkce bgChange() ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol ;)

    Nejstarší metoda registrace obslužných rutin událostí nalezená na webu zahrnovala atributy HTML obslužných rutin událostí (nebo vložené obslužné rutiny událostí ), jako je ta, která je uvedena výše – hodnota atributu je doslova kód JavaScript, který chcete spustit, když dojde k události. Výše uvedený příklad vyvolá funkci definovanou uvnitř prvku na stejné stránce, ale můžete také vložit JavaScript přímo do atributu, například:

    Stiskněte mě

    Pro mnoho vlastností obsluhy události můžete najít ekvivalenty atributů HTML; neměli byste je však používat – jsou považovány za špatný postup. Může se zdát snadné použít atribut obsluhy události, pokud děláte něco opravdu rychlého, ale velmi rychle se stanou neovladatelnými a neúčinnými.

    Pro začátek není dobrý nápad zaměňovat HTML a JavaScript, protože je obtížné je analyzovat – lepší je mít JavaScript celý na jednom místě; pokud je v samostatném souboru, můžete jej použít na více dokumentů HTML.

    Ani v jediném souboru nejsou vložené obslužné rutiny událostí dobrý nápad. Jedno tlačítko je v pořádku, ale co kdybyste měli 100 tlačítek? Do souboru byste museli přidat 100 atributů; velmi rychle by se to změnilo v údržbu. S JavaScriptem byste mohli snadno přidat funkci obsluhy událostí ke všem tlačítkům na stránce bez ohledu na to, kolik jich bylo, pomocí něčeho jako tento:

    Const buttons = document.querySelectorAll("tlačítko"); for (ať i = 0; i< buttons.length; i++) { buttons[i].onclick = bgChange; } buttons.forEach(function(button) { button.onclick = bgChange; });

    Poznámka: Díky oddělení logiky programování od obsahu bude váš web také přátelštější pro vyhledávače.

    addEventListener() a removeEventListener()

    Nejnovější typ mechanismu událostí je definován ve specifikaci událostí Document Object Model (DOM) úrovně 2, která poskytuje prohlížečům novou funkci - addEventListener() . Funguje to podobně jako vlastnosti obsluhy události, ale syntaxe je samozřejmě odlišná. Náš náhodný barevný příklad bychom mohli přepsat, aby vypadal takto:

    Const btn = document.querySelector("tlačítko"); funkce bgChange() ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol; ) btn.addEventListener("click", bgChange);

    Uvnitř funkce addEventListener() zadáváme dva parametry – název události, pro kterou chceme tento handler zaregistrovat, a kód, který obsahuje funkci handleru, kterou chceme spustit jako odpověď na něj. Všimněte si, že je naprosto vhodné vložit veškerý kód do funkce addEventListener() do anonymní funkce, jako je tato:

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

    Tento mechanismus má některé výhody oproti starším mechanismům diskutovaným výše. Pro začátek je zde protějšek funkce removeEventListener() , která odebere dříve přidaný posluchač. To by například odstranilo sadu posluchačů v prvním bloku kódu v této části:

    Btn.removeEventListener("click", bgChange);

    U jednoduchých, malých programů to není podstatné, ale u větších a složitějších programů to může zlepšit efektivitu při čištění starých nepoužívaných obslužných programů událostí. Navíc vám to například umožňuje mít stejné tlačítko za různých okolností pro různé akce – vše, co musíte udělat, je přidat nebo odebrat obslužné rutiny událostí podle potřeby.

    Za druhé, můžete také zaregistrovat více obslužných programů pro stejný posluchač. Následující dva obslužné nástroje by nebyly použity oba:

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

    Druhý řádek přepíše hodnotu onclick nastavenou na prvním řádku. To by však fungovalo:

    MyElement.addEventListener("click", functionA); myElement.addEventListener("kliknutí", funkceB);

    Obě funkce by se nyní spustily po kliknutí na prvek.

    Kromě toho je s tímto mechanismem událostí k dispozici řada dalších výkonných funkcí a možností. Ty jsou trochu mimo rozsah tohoto článku, ale pokud si je chcete přečíst, podívejte se na referenční stránky addEventListener() a removeEventListener().

    Jaký mechanismus bych měl použít?

    Z těchto tří mechanismů byste rozhodně neměli používat atributy obsluhy událostí HTML – ty jsou zastaralé a špatné, jak je uvedeno výše.

    Další dva jsou relativně zaměnitelné, alespoň pro jednoduché použití:

    • Vlastnosti obsluhy událostí mají menší výkon a možnosti, ale lepší kompatibilitu mezi prohlížeči (podporovány již od internet Explorer 8). Pravděpodobně byste s nimi měli začít, když se učíte.
    • Události DOM úrovně 2 (addEventListener() atd.) jsou výkonnější, ale mohou se také stát složitějšími a jsou méně dobře podporovány (podporovány již od aplikace Internet Explorer 9). Měli byste s nimi také experimentovat a snažit se je používat, kde je to možné.

    Hlavní výhody třetího mechanismu spočívají v tom, že v případě potřeby můžete odstranit kód obsluhy události pomocí removeEventListener() a v případě potřeby můžete k prvkům přidat více posluchačů stejného typu. Můžete například volat addEventListener("click", function() ( ... )) na prvek vícekrát s různými funkcemi specifikovanými ve druhém argumentu. To není možné s vlastnostmi obsluhy události, protože jakékoli následné pokusy o nastavení vlastnosti přepíší ty dřívější, např.:

    Element.onclick = function1; element.onclick = function2; atd.

    Poznámka: Pokud jste vyzváni, abyste při své práci podporovali prohlížeče starší než Internet Explorer 8, můžete narazit na potíže, protože takové staré prohlížeče používají jiné modely událostí než novější prohlížeče. Ale nebojte se, většina knihoven JavaScriptu (například jQuery) má vestavěné funkce, které abstrahují rozdíly mezi různými prohlížeči. Nedělejte si s tím v této fázi své cesty učení příliš velké starosti.

    Další koncepty událostí

    V této části stručně pokryjeme některé pokročilé koncepty, které jsou relevantní pro události. V tuto chvíli není důležité těmto pojmům plně porozumět, ale mohou posloužit k vysvětlení některých vzorců kódu, se kterými se čas od času pravděpodobně setkáte.

    Objekty událostí

    Někdy uvnitř funkce obsluhy události můžete vidět parametr zadaný s názvem, jako je event , evt nebo jednoduše e . Říká se tomu objekt události a je automaticky předán obslužným rutinám událostí, které poskytují další funkce a informace. Přepišme například náš příklad náhodné barvy znovu mírně:

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

    Zde můžete vidět, že do funkce zahrneme objekt události, e , a do funkce nastavíme styl barvy pozadí na e.target - což je samotné tlačítko. Vlastnost target objektu události je vždy odkazem na prvek, u kterého událost právě nastala. V tomto příkladu tedy nastavujeme náhodnou barvu pozadí na tlačítku, nikoli na stránce.

    Poznámka: Pro objekt události můžete použít libovolný název – stačí si vybrat název, který pak můžete použít k odkazování ve funkci obsluhy události. e/evt/event nejčastěji používají vývojáři, protože jsou krátké a snadno zapamatovatelné. Vždy je dobré být konzistentní – sám se sebou a pokud možno s ostatními.

    e.target je neuvěřitelně užitečný, když chcete nastavit stejnou obslužnou rutinu události pro více prvků a udělat něco se všemi, když na nich dojde k události. Můžete mít například sadu 16 dlaždic, které zmizí, když na ně kliknete. Je užitečné mít vždy možnost jednoduše nastavit, aby věc zmizela jako e.target , místo toho, abyste ji museli vybírat nějakým složitějším způsobem. V následujícím příkladu (úplný zdrojový kód naleznete na adrese užitečné-eventtarget.html; zde také můžete vidět, jak běží živě), vytvoříme 16 prvků pomocí JavaScriptu. Poté je všechny vybereme pomocí document.querySelectorAll() , poté projdeme každou z nich a ke každé přidáme obslužnou rutinu onclick, díky které se po kliknutí použije náhodná barva:

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

    Výstup je následující (zkuste na něj kliknout - bavte se):

    Skrytý příklad Užitečný příklad cíle události div ( výška: 100px; šířka: 25 %; plovoucí: vlevo; ) pro (let i = 1; i
  • Tužka
  • Pero
  • guma

  • Nyní, když víme, že každé kliknutí na tlačítko se objeví přes prvek ul.toolbar, připojme k němu naši obsluhu události. Naštěstí už to máme:

    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. remove("aktivní"); ));
    Nyní máme mnohem čistší kód a dokonce jsme se zbavili smyček! Všimněte si však, že jsme nahradili e.currentTarget za e.target . Důvod spočívá v tom, že zpracováváme události na jiné úrovni.

    e.target je skutečný cíl události, kde si razí cestu přes DOM a odkud pak vybuchne.
    e.currentTarget - aktuální prvek, který zpracovává událost. V našem případě je to ul.toolbar.

    Vylepšené vyskakovací události V současné době zpracováváme jakékoli kliknutí na každý prvek, který se objeví, prostřednictvím ul.toolbar , ale naše podmínka ověření je příliš jednoduchá. Co by se stalo, kdybychom měli složitější DOM, který by obsahoval ikony a prvky, na které se neklikalo?

    • Tužka
    • Pero
    • guma

    Jejda! Nyní, když klikneme na li.separator nebo ikonu, přidáme k ní třídu .active. Přinejmenším to není dobré. Potřebujeme způsob, jak filtrovat události, abychom reagovali na prvek, který potřebujeme.

    Vytvořme si k tomu malou pomocnou funkci:

    Var delegát = function(kritéria, posluchač) ( return function(e) ( var el = e.target; do ( if (!criteria(el)) pokračovat; e.delegateTarget = el; listener.apply(toto, argumenty); return; ) while((el = el.parentNode)); ); );
    Náš asistent dělá dvě věci. Nejprve iteruje každý prvek a jeho rodiče a zkontroluje, zda splňují podmínku zadanou v parametru kritéria. Pokud prvek vyhovuje, pomocník přidá do objektu události pole nazvané delegátTarget, ve kterém je uložen prvek, který splňuje naše podmínky. A pak zavolá psovoda. Pokud tedy žádný prvek nesplňuje podmínku, nebude volána žádná obsluha.

    Můžeme to použít takto:

    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("kliknutí", delegát(buttonsFilter, buttonHandler));
    Přesně to, co doktor nařídil: jedna obsluha události připojená k jednomu prvku, který dělá veškerou práci. Ale dělá to jen pro prvky, které potřebujeme. A perfektně reaguje na přidávání a odebírání objektů z DOM.

    Shrnutí Stručně jsme se podívali na základy implementace delegování (zpracování vyskakovacích) událostí v čistém JavaScriptu. To je dobré, protože nepotřebujeme generovat a připojovat spoustu handlerů pro každý prvek.

    Pokud bych z toho chtěl vytvořit knihovnu nebo použít kód ve vývoji, přidal bych pár věcí:

    Pomocná funkce pro kontrolu, zda objekt splňuje kritéria v jednotnější a funkčnější podobě. Jako:

    Var kritéria = ( isElement: function(e) ( return e instanceof HTMLElement; ), hasClass: function(cls) ( return function(e) ( return kritéria.isElement(e) && e.classList.contains(cls); ) ) //Další kritéria);
    Částečné využití asistenta by bylo také užitečné:

    Var parcialDelgate = function(kriteria) ( return function(handler) ( return delgate(criteria, handler); ) );
    Původní článek: Understanding Delegated JavaScript Events
    (Od překladatele: můj první, posuzujte přísně.)

    Šťastné kódování!

    Ahoj! V této lekci chci mluvit o tak důležitém konceptu, jako je vynořování a zachycení událostí. Bublinkování je jev, kdy pokud kliknete na podřízený prvek, událost se rozšíří k jeho nadřazenému prvku.

    To může být velmi užitečné při zpracování velkých vnořených seznamů nebo tabulek; abyste nepřiřazovali obsluhu události každému prvku, můžete nadřazenému prvku přiřadit jednu obsluhu a událost se již rozšíří na všechny vnořené prvky v nadřazeném prvku. Podívejme se na příklad.

    Tento obslužný program se spustí, když kliknete na dílčí značku nebo:

    Klikněte na EM, handler na DIV bude fungovat

    Jak můžete vidět, když kliknete na vnořený prvek em, spustí se obslužná rutina prvku div. Proč se tohle děje? Čtěte dál a zjistěte.

    Výstup

    Takže základní princip výstupu:

    Když dojde k jakékoli události, nezáleží na tom, zda se na prvek klikne myší, událost se nejprve spustí na nadřazeném prvku a poté se v řetězci rozšíří na všechny vnořené prvky.

    Předpokládejme například, že existují 3 vnořené prvky FORM > DIV > P, s obslužnou rutinou události na každém z nich:

    tělo * ( okraj: 10px; okraj: 1px plný modrý; ) FORM DIV

    Bublinkování zajišťuje kliknutí na vnitřní prvek

    Nejprve zavolá obslužnou rutinu kliknutí (pokud samozřejmě existuje).

    Tento proces se nazývá vzestup, protože se zdá, že události „vznášejí se“ z vnitřního prvku nahoru prostřednictvím svých rodičů, stejně jako vzduchová bublina vznáší se ve vodě, takže můžete také najít definici bublání, dobře, je to jen z angličtiny slovo bublat - vznášet se.

    Přístup k cílovému prvku event.target

    Abychom zjistili, na kterém prvku jsme zachytili tu či onu událost, existuje metoda event.target. (přečtěte si o objektu události).

    • event.target je skutečný zdrojový prvek, na kterém k události došlo.
    • vždy se jedná o aktuální prvek, kterého bublání dosáhlo, a na něm právě běží handler.

    Pokud máte například nainstalovaný pouze jeden obslužný program form.onclick, „zachytí“ všechna kliknutí uvnitř formuláře. Navíc bez ohledu na to, kde je klik uvnitř, stále vyskočí na prvek, na kterém bude handler pracovat.

    kde:

    • toto (=event.currentTarget) bude vždy samotný formulář, protože na něm byl spuštěn handler.
    • event.target bude obsahovat odkaz na konkrétní prvek ve formuláři, nejvíce vnořený prvek, na který došlo ke kliknutí.

    V zásadě se to může shodovat s event.target, pokud se na formulář klikne a ve formuláři nejsou žádné další prvky.

    Zastavení stoupání

    Obvykle se bublání události dostane přímo nahoru a dosáhne objektu kořenového okna.

    Ale je možné zastavit výstup na nějakém mezičlánku.

    Chcete-li zastavit šíření, musíte zavolat metodu event.stopPropagation().

    Podívejme se na příklad: při kliknutí na tlačítko nebude obslužný program body.onclick fungovat:

    Klikni na mě

    Pokud má prvek pro stejnou událost nainstalováno několik obslužných rutin, pak i když bublání ustane, budou provedeny všechny.

    StopPropagation tedy zabrání dalšímu šíření události, ale všechny handlery budou pracovat na prvku, ale ne na dalším prvku.

    Chcete-li zastavit zpracování na aktuálním prvku, prohlížeče podporují metodu event.stopImmediatePropagation(). Tato metoda nejen zabrání bublání, ale také zastaví zpracování události na aktuálním prvku.

    Potápět

    Ve standardu je kromě „vzestupu“ akcí také „ponoření“.

    Potápění je na rozdíl od výstupu méně žádané, ale i tak se bude hodit vědět o něm.

    Akce má tedy 3 fáze:

  • Událost probíhá shora dolů. Tato fáze se nazývá „etapa zachycení“.
  • Událost dosáhla konkrétního prvku. Toto je „cílová fáze“.
  • Po tom všem se událost začíná vynořovat. Toto je „stupeň výstupu“.
  • Ve standardu je to demonstrováno takto:

    Když tedy kliknete na TD, událost se přesune po řetězu rodičů, nejprve dolů k elementu („potopí se“) a pak nahoru („vyskočí“), přičemž se po cestě podle toho použijí ovladače.

    Výše jsem psal pouze o stoupání, protože ostatní stupně se nepoužívají a procházejí námi bez povšimnutí.

    Psovodi o záchytné fázi nic nevědí, ale začínají pracovat od stoupání.

    A abyste zachytili událost ve fázi zachycení, stačí použít:

    • Argument je pravdivý, pak bude událost zachycena cestou dolů.
    • Argument je nepravdivý, pak bude událost zachycena při bublání.
    Příklady

    V příkladu na , ,

    Procesory jsou stejné 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.

    Zde je kód JS:

    Var elems = document.querySelectorAll("form,div,p"); // připojí obsluhu ke každému prvku ve fázi zachycení pro (var i = 0; i< elems.length; i++) { elems[i].addEventListener("click", highlightThis, true); }


    Nikdo vám nebrání v přidělování handlerů pro obě fáze, jako je tento:

    Var elems = 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í událostí:
    Mělo by to 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 z kořenového adresáře dokumentu dolů do event.target, přičemž během cesty zavolá obslužné programy dodávané prostřednictvím addEventListener(…., true).
    • Událost se přesouvá z event.target na začátek dokumentu a zároveň volá handlery dodané přes addEventListener(…., false).

    Každý obslužný program bude mít přístup k vlastnostem události:

    • event.target je nejhlubší prvek, kde k události skutečně došlo.
    • event.currentTarget (=toto) – prvek, na kterém je self-handler aktuálně spuštěn (na který událost „dosáhla“).
    • event.eventPhase – v jaké fázi byla obsluha události spuštěna (ponor = 1, vzestup = 3).

    Šíření lze zastavit voláním metody event.stopPropagation(), ale to se nedoporučuje, protože událost můžete potřebovat pro nejneočekávanější účely.