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
akeyup
– 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ě:
-
Pouze HTML:
<input type="button" onclick="alert('Click!')" value="Button">
-
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
:pokudtrue
, 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
:pokudtrue
, pak handler nebude volatpreventDefault()
, 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ů.
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 zevent.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í:
- Atribut HTML:
onclick="..."
. - Vlastnost DOM:
elem.onclick = function
. - Metody:
elem.addEventListener(event, handler[, phase])
přidatremoveEventListener
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.