Probublávání událostí, potlačení další obsluhy
Většina událostí, které vznikají někde ve stromě DOM, „probublávají“ (též se to označuje jako „propagace“) směrem vzhůru. Pokud se například klikne na obrázek v odstavci, lze událost obsloužit nejdřív v obrázku. Pak událost probublá do odstavce a lze ji obsloužit tam. Takhle může probublat až do kořene (objektu document
).
Existují události, které ve všech nebo v některých prohlížečích neprobublávají. Ovšem jQuery řeší prohlížečově specifické věci svými prostředky a tak například událost change
bublá vzhůru i v prohlížeči Internet Explorer (verze 8 a nižší), i když by se tak normálně nestalo.
Většinou je žádoucí, aby události takto probublávaly, někdy se to ale nehodí. Proto lze tento proces zastavit. Mějme třeba zmíněný obrázek v odstavci:
<p> <img src="obrazek.jpg" alt="Obrázek" id="img"> </p>
Budeme obsluhovat kliknutí a nechceme, aby událost probublala do odstavce:
$('#img').click(function(e) { e.stopPropagation(); ... }
Všimněte si, že se tu využívá instance objektu události (Event
), který může posloužit jak pro volání metod, tak pro získávání zajímavých informací (viz dále). Tady se mu zavolá metoda stopPropagation()
, která probublávání zastaví. Lze ji zavolat i pro události, které probublaly z níže umístěných objektů ve stromě.
Uvedená metoda však nezastaví zavolání dalších obslužných metod navázaných přímo na daném objektu. Pokud by to bylo nutné, lze použít metodu stopImmediatePropagation()
. Není to však dobrá praxe – takový kód se špatně ladí, pokud něco nefunguje.
Podobné je to s výchozí obsluhou (definovanou „natvrdo“ v prohlížeči). Tu lze sice zakázat metodou preventDefault()
, ovšem je potřeba to používat s opatrností, protože ne všechny výchozí obsluhy lze potlačit, odlišnosti jsou i mezi prohlížeči.
Ještě je tu jedna zajímavá možnost, jak ovlivnit obsluhu událostí:
$('#img').click(function() { ... return false; }
Takové řešení se chová, jako kdyby se zavolaly metody stopPropagation()
a preventDefault()
. Událost tedy nebublá výše, ani se pro ni nezavolá výchozí obsluha. Explicitně nastavené obslužné funkce se však zavolají. Tohle se v praxi používá relativně často (byť i zde je samozřejmě na místě opatrnost), typicky právě pro událost kliknutí – většinou u odkazů, kde měníme jejich výchozí chování na nějaké vlastní.
Místo metody vracející vždycky false lze jako obslužnou funkci předat přímo hodnotu false. Sémanticky je to úplně stejné, jen se zjednoduší zápis.
Delegovaná obsluha událostí
Delegované obsluze byl v minulém dílu věnován příklad. Při delegaci se využívá právě výše popsaný efekt probublávání, takže z toho vyplývají i další souvislosti. Například pokud se někde nastaví přímá obsluha a v ní se zakáže probublávání, přestane fungovat delegovaná obsluha.
Dále může delegovaná obsluha klást vyšší požadavky na zjišťování informací. Přes klíčové slovo this se totiž dostaneme nikoli k objektu, na kterém událost nastala (jako je to u přímé obsluhy), nýbrž k tomu, kde se obsluhuje. Potřebujeme-li se dostat k objektu přímo spjatém s událostí jako takovou, musí se na to jít jinak.
$('p').on('click', 'img', function(e) { var o = e.target; ... });
Poslouží k tomu již zmíněný objekt typu Event
, který poskytuje kromě jiného položku target
. Tam se nachází objekt typu Element
(podobně jako v this
), se kterým lze dále pracovat – ať už přímo nebo vytvořením instance jQuery
. U přímo obsluhovaných událostí tam bude samozřejmě totéž jako přes this
.
Objekt události obsahuje ještě dvě další podobné položky. Jednak je to currentTarget
– to je element, kde se aktuálně událost obsluhuje (tedy totéž jako this
). Zajímavější je ale delegateTarget
, protože umožňuje už dopředu určit, kde se bude událost delegovaně obsluhovat – a třeba tuto obsluhu zrušit. Pro nedelegovanou obsluhu mají obě položky (resp. všechny tři) samozřejmě stejnou hodnotu.
Objekt události, předávání dat
Již zmíněný objekt třídy Event toho obsahuje mnohem víc. Mezi nejzajímavější položky patří tyto:
type
– typ události (řetězec použitý pro nastavení von()
, napříkladclick
)pageX
,pageY
– pozice kurzoru myši relativně k dokumenturesult
– výsledek předchozí volání obsluhywhich
– stisknutá klávesa nebo tlačítko myšidata
– data předaná při nastavování obsluhy, viz dále
Existují i další položky. V závislosti na konkrétní události a dalších okolnostech se liší množina položek, jejichž hodnoty jsou definovány (nedefinované jsou samozřejmě typu undefined
). Například result
není definována, pokud nebyla volána nějaká obsluha vracející konkrétní hodnotu.
$('body').on('click', 'img', function(e) { alert('x=' + e.pageX + ', y=' + e.pageY); });
Příklad ukazuje jednoduché využití dat z objektu události kliknutí na obrázek. Událost se obsluhuje v delegovaném režimu, což umožňuje zpracovávat i kliknutí na všechny později přidané obrázky. Po kliknutí vyskočí zpráva se souřadnicemi (v rámci dokumentu), kam se kliklo.
Jak předávat data do obslužné funkce
Zvlášť zajímavé je ale využití položky data, přes kterou lze do obslužné funkce přenést libovolná data „zvenčí“. Ne vždy si totiž vystačíme s tím, co lze získat přímo z objektu události nebo elementu, případně by to bylo zbytečně komplikované. Můžeme proto udělat něco jako toto:
var o = { x: 100, y: 200 }; $('body').on('click', 'img', o, function(e) { alert('x=' + (e.pageX + e.data.x) + ', y=' + (e.pageY + e.data.y)); });
Příklad je stejný jako ten výše, předává se ovšem ještě „offset“, o který se mají souřadnice přepočítat. Obslužná funkce je dostane přes objekt události. Význam by to mělo hlavně u neanonymní funkce (protože tam se využije variabilita tohoto řešení), ale pro snazší pochopení je příklad opět s funkcí anonymní. Při nastavení obsluhy tedy volíme data (může to být třeba i pouhé číslo nebo řetězec), která se předají do obsluhy.
Předávání dat při explicitním vyvolání události
Data lze předávat také při vyvolání události, například metodou trigger()
– viz minulý díl. Tady to bude fungovat trochu jinak, data se předají přes parametry obslužné funkce. Ta by se nastavila například takto:
$('img').on('mouseenter', function(e, debug) { if (typeof debug != 'undefined' && debug) { alert('Simulace najetí myší'); } ... });
Tato obsluha je implementovaná tak, že umožňuje předat informaci o tom, zda jde o ladicí režim (pak se uživateli zobrazí zpráva). V obslužné funkci tedy přibyl parametr debug
. Pokud je definován a má hodnotu true
, je obsluha volána v ladicím režimu. Událost by se pak vyvolala následovně:
$('img#test').trigger('mouseenter', true);
Událost vyvolaná s hodnotou false
nebo skutečným najetí myší by v ladicím režimu nebyla. Parametrů může být předáno více – u obslužné funkce se prostě přidají na konec, ve volání trigger()
se ale musí vložit do pole.
Požadavky na server a nastavování obsluhy v objektu
Na zbývající věci okolo obsluhy událostí se podíváme příště. Bude to nastavování obsluhy přes položky objektu. Bude nejlepší si to ukázat na komunikaci se serverem, kdy lze nastavit obsluhu široké palety událostí.