Úvod do událostí prohlížeče

Událost je signál, že se něco stalo. Všechny uzly DOM generují takové signály (ale události nejsou omezeny na DOM).

Zde je seznam nejužitečnějších událostí DOM, stačí se podívat na:

Události myši:

  • click – když klepnete myší na prvek (zařízení s dotykovou obrazovkou jej vygenerují klepnutím).
  • contextmenu – když klepnete pravým tlačítkem myši na prvek.
  • mouseover / mouseout – když kurzor myši najede na / opustí prvek.
  • mousedown / mouseup – při stisknutí / uvolnění tlačítka myši nad prvkem.
  • mousemove – při pohybu myší.

Události klávesnice:

  • keydown a keyup – při stisknutí a uvolnění klávesy na klávesnici.

Události prvků formuláře:

  • submit – když návštěvník odešle <form> .
  • focus – když se návštěvník zaměří na prvek, např. na <input> .

Události dokumentu:

  • DOMContentLoaded – když je HTML načteno a zpracováno, DOM je plně vytvořen.

Události CSS:

  • transitionend – když skončí animace CSS.

Existuje mnoho dalších akcí. Více podrobností o konkrétních událostech probereme v dalších kapitolách.

Obslužné nástroje událostí

K reakci na události můžeme přiřadit handler – funkce, která se spustí v případě události.

Obslužné rutiny představují způsob, jak spustit kód JavaScript v případě uživatelských akcí.

Existuje několik způsobů, jak přiřadit handler. Pojďme se na ně podívat, počínaje tím nejjednodušším.

HTML-atribut

Obslužnou rutinu lze nastavit v HTML pomocí atributu s názvem on<event> .

Chcete-li například přiřadit click handler pro input , můžeme použít onclick , jako zde:

<input value="Click me" onclick="alert('Click!')" type="button">

Po kliknutí myší se kód uvnitř onclick běží.

Všimněte si prosím, že uvnitř onclick používáme jednoduché uvozovky, protože samotný atribut je ve dvojitých uvozovkách. Pokud zapomeneme, že kód je uvnitř atributu a použijeme uvnitř dvojité uvozovky, jako je tento:onclick="alert("Click!")" , pak to nebude fungovat správně.

Atribut HTML není vhodné místo pro psaní velkého množství kódu, takže bychom měli vytvořit funkci JavaScript a zavolat ji tam.

Zde kliknutím spustíte funkci countRabbits() :

<script>
 function countRabbits() {
 for(let i=1; i<=3; i++) {
 alert("Rabbit number " + i);
 }
 }
</script>

<input type="button" onclick="countRabbits()" value="Count rabbits!">

Jak víme, názvy atributů HTML nerozlišují velká a malá písmena, takže ONCLICK funguje stejně jako onClick a onCLICK … Ale atributy jsou obvykle psány malými písmeny:onclick .

Vlastnost DOM

Obslužnou rutinu můžeme přiřadit pomocí vlastnosti DOM on<event> .

Například elem.onclick :

<input id="elem" type="button" value="Click me">
<script>
 elem.onclick = function() {
 alert('Thank you');
 };
</script>

Pokud je handler přiřazen pomocí atributu HTML, prohlížeč jej přečte, vytvoří novou funkci z obsahu atributu a zapíše ji do vlastnosti DOM.

Takže tento způsob je vlastně stejný jako ten předchozí.

Tyto dvě části kódu fungují stejně:

  1. Pouze HTML:

    <input type="button" onclick="alert('Click!')" value="Button">
  2. HTML + JS:

    <input type="button" id="button" value="Button">
    <script>
     button.onclick = function() {
     alert('Click!');
     };
    </script>

V prvním příkladu je atribut HTML použit k inicializaci button.onclick , zatímco ve druhém příkladu – skriptu, je to celý rozdíl.

Protože existuje pouze jeden onclick vlastnost, nemůžeme přiřadit více než jednu obsluhu události.

V níže uvedeném příkladu přidání obslužné rutiny pomocí JavaScriptu přepíše stávající obslužnou rutinu:

<input type="button" id="elem" onclick="alert('Before')" value="Click me">
<script>
 elem.onclick = function() { // overwrites the existing handler
 alert('After'); // only this will be shown
 };
</script>

Chcete-li odstranit handler, přiřaďte elem.onclick = null .

Přístup k prvku:toto

Hodnota this uvnitř handleru je prvek. Ten, který má na sobě handler.

V níže uvedeném kódu button zobrazuje jeho obsah pomocí this.innerHTML :

<button onclick="alert(this.innerHTML)">Click me</button>

Možné chyby

Pokud začínáte pracovat s událostmi – všimněte si prosím některých jemností.

Můžeme nastavit existující funkci jako handler:

function sayThanks() {
 alert('Thanks!');
}

elem.onclick = sayThanks;

Ale buďte opatrní:funkce by měla být přiřazena jako sayThanks , nikoli sayThanks() .

// right
button.onclick = sayThanks;

// wrong
button.onclick = sayThanks();

Pokud přidáme závorky, pak sayThanks() stane voláním funkce. Takže poslední řádek ve skutečnosti přebírá výsledek provedení funkce, to je undefined (protože funkce nevrací nic) a přiřadí ji onclick . To nefunguje.

…Na druhou stranu, v označení potřebujeme závorky:

<input type="button" id="button" onclick="sayThanks()">

Rozdíl lze snadno vysvětlit. Když prohlížeč čte atribut, vytvoří z obsahu atributu funkci handleru s tělem.

Takže označení generuje tuto vlastnost:

button.onclick = function() {
 sayThanks(); // <-- the attribute content goes here
};

Nepoužívejte setAttribute pro psovody.

Takový hovor nebude fungovat:

// a click on <body> will generate errors,
// because attributes are always strings, function becomes a string
document.body.setAttribute('onclick', function() { alert(1) });

Na případu vlastnosti DOM záleží.

Přiřaďte obslužnou rutinu elem.onclick , nikoli elem.ONCLICK , protože vlastnosti DOM rozlišují velká a malá písmena.

addEventListener

Základní problém výše uvedených způsobů přidělování handlerů – nemůžeme přiřadit více handlerů jedné události.

Řekněme, že jedna část našeho kódu chce zvýraznit tlačítko při kliknutí a druhá chce při stejném kliknutí zobrazit zprávu.

K tomu bychom rádi přidělili dva obslužné rutiny událostí. Ale nová vlastnost DOM přepíše stávající vlastnost:

input.onclick = function() { alert(1); }
// ...
input.onclick = function() { alert(2); } // replaces the previous handler

Vývojáři webových standardů to pochopili již dávno a navrhli alternativní způsob správy handlerů pomocí speciálních metod addEventListener a removeEventListener . Nemají takový problém.

Syntaxe pro přidání obsluhy:

element.addEventListener(event, handler, [options]);
event
Název události, např. "click" .
handler
Funkce obsluhy.
options
Další volitelný objekt s vlastnostmi:
  • once :pokud true , pak je posluchač po spuštění automaticky odstraněn.
  • capture :fáze, kde se má událost zpracovat, bude popsána později v kapitole Probublávání a zachycení. Z historických důvodů options může být také false/true , to je stejné jako {capture: false/true} .
  • passive :pokud true , pak handler nebude volat preventDefault() , to vysvětlíme později ve výchozích akcích prohlížeče.

Chcete-li ovladač odebrat, použijte removeEventListener :

element.removeEventListener(event, handler, [options]);
Odstranění vyžaduje stejnou funkci

Chcete-li odstranit handler, měli bychom předat přesně stejnou funkci, jaká byla přiřazena.

Toto nefunguje:

elem.addEventListener( "click" , () => alert('Thanks!'));
// ....
elem.removeEventListener( "click", () => alert('Thanks!'));

Obslužný nástroj nebude odstraněn, protože removeEventListener získá jinou funkci – se stejným kódem, ale na tom nezáleží, protože se jedná o jiný funkční objekt.

Zde je správný způsob:

function handler() {
 alert( 'Thanks!' );
}

input.addEventListener("click", handler);
// ....
input.removeEventListener("click", handler);

Vezměte prosím na vědomí – pokud funkci neuložíme do proměnné, nemůžeme ji odstranit. Neexistuje žádný způsob, jak „přečíst zpět“ obslužné nástroje přiřazené addEventListener .

Vícenásobná volání na číslo addEventListener povolit přidání více obslužných rutin, jako je tento:

<input id="elem" type="button" value="Click me"/>

<script>
 function handler1() {
 alert('Thanks!');
 };

 function handler2() {
 alert('Thanks again!');
 }

 elem.onclick = () => alert("Hello");
 elem.addEventListener("click", handler1); // Thanks!
 elem.addEventListener("click", handler2); // Thanks again!
</script>

Jak vidíme v příkladu výše, můžeme nastavit handlery obě pomocí vlastnosti DOM a addEventListener . Ale obecně používáme pouze jeden z těchto způsobů.

U některých událostí obslužné programy pracují pouze s addEventListener

Existují události, které nelze přiřadit prostřednictvím vlastnosti DOM. Pouze s addEventListener .

Například DOMContentLoaded událost, která se spustí při načtení dokumentu a sestavení DOM.

// will never run
document.onDOMContentLoaded = function() {
 alert("DOM built");
};
// this way it works
document.addEventListener("DOMContentLoaded", function() {
 alert("DOM built");
});

Takže addEventListener je univerzálnější. I když jsou takové události spíše výjimkou než pravidlem.

Objekt události

Abychom správně zvládli událost, chtěli bychom vědět více o tom, co se stalo. Nejen „kliknutí“ nebo „stisknutí klávesy“, ale jaké byly souřadnice ukazatele? Která klávesa byla stisknuta? A tak dále.

Když dojde k události, prohlížeč vytvoří objekt události , vloží do něj podrobnosti a předá jej jako argument handleru.

Zde je příklad získání souřadnic ukazatele z objektu události:

<input type="button" value="Click me" id="elem">

<script>
 elem.onclick = function(event) {
 // show event type, element and coordinates of the click
 alert(event.type + " at " + event.currentTarget);
 alert("Coordinates: " + event.clientX + ":" + event.clientY);
 };
</script>

Některé vlastnosti event objekt:

event.type
Typ události, zde je "click" .
event.currentTarget
Prvek, který událost zpracoval. To je úplně stejné jako this , pokud není obslužnou rutinou funkce šipky nebo její this je vázán na něco jiného, ​​pak můžeme získat prvek z event.currentTarget .
event.clientX / event.clientY
Souřadnice kurzoru relativní k oknu, pro události ukazatele.

Nemovitostí je více. Mnoho z nich závisí na typu události:události klávesnice mají jednu sadu vlastností, události ukazatele – další, prostudujeme je později, až se dostaneme k různým událostem podrobněji.

Objekt události je také dostupný v obslužných programech HTML

Pokud přiřadíme handler v HTML, můžeme také použít event objekt, jako je tento:

<input type="button" onclick="alert(event.type)" value="Event type">

To je možné, protože když prohlížeč čte atribut, vytvoří obslužnou rutinu jako je tento:function(event) { alert(event.type) } . To znamená:jeho první argument se nazývá "event" a tělo je převzato z atributu.

Obsluhy objektů:handleEvent

Můžeme přiřadit nejen funkci, ale i objekt jako obsluhu události pomocí addEventListener . Když nastane událost, její handleEvent se nazývá metoda.

Například:

<button id="elem">Click me</button>

<script>
 let obj = {
 handleEvent(event) {
 alert(event.type + " at " + event.currentTarget);
 }
 };

 elem.addEventListener('click', obj);
</script>

Jak vidíme, když addEventListener přijme objekt jako handler, zavolá obj.handleEvent(event) v případě události.

K tomu bychom také mohli použít třídu:

<button id="elem">Click me</button>

<script>
 class Menu {
 handleEvent(event) {
 switch(event.type) {
 case 'mousedown':
 elem.innerHTML = "Mouse button pressed";
 break;
 case 'mouseup':
 elem.innerHTML += "...and released.";
 break;
 }
 }
 }

 let menu = new Menu();
 elem.addEventListener('mousedown', menu);
 elem.addEventListener('mouseup', menu);
</script>

Zde stejný objekt zpracovává obě události. Upozorňujeme, že musíme explicitně nastavit události tak, aby naslouchaly pomocí addEventListener . menu objekt získá pouze mousedown a mouseup zde, žádné jiné typy událostí.

Metoda handleEvent nemusí dělat všechnu práci sám. Místo toho může volat jiné metody specifické pro událost, jako je tato:

<button id="elem">Click me</button>

<script>
 class Menu {
 handleEvent(event) {
 // mousedown -> onMousedown
 let method = 'on' + event.type[0].toUpperCase() + event.type.slice(1);
 this[method](event);
 }

 onMousedown() {
 elem.innerHTML = "Mouse button pressed";
 }

 onMouseup() {
 elem.innerHTML += "...and released.";
 }
 }

 let menu = new Menu();
 elem.addEventListener('mousedown', menu);
 elem.addEventListener('mouseup', menu);
</script>

Nyní jsou obslužné rutiny událostí jasně odděleny, což může být jednodušší na podporu.

Shrnutí

Existují 3 způsoby, jak přiřadit obslužné rutiny událostí:

  1. Atribut HTML:onclick="..." .
  2. Vlastnost DOM:elem.onclick = function .
  3. Metody:elem.addEventListener(event, handler[, phase]) přidat removeEventListener odstranit.

Atributy HTML se používají střídmě, protože JavaScript uprostřed značky HTML vypadá trochu zvláštně a cize. Také tam nelze napsat mnoho kódu.

Vlastnosti DOM lze použít, ale nemůžeme přiřadit více než jeden handler konkrétní události. V mnoha případech toto omezení netlačí.

Poslední způsob je nejflexibilnější, ale také nejdelší na psaní. Existuje jen málo událostí, které fungují pouze s ním, například transitionend a DOMContentLoaded (k pokrytí). Také addEventListener podporuje objekty jako obslužné rutiny událostí. V tom případě metoda handleEvent je volána v případě události.

Bez ohledu na to, jak obslužnou rutinu přiřadíte – jako první argument získá objekt události. Tento objekt obsahuje podrobnosti o tom, co se stalo.

Více o událostech obecně ao různých typech událostí se dozvíme v dalších kapitolách.