Na obzoru je vydání nové verze Internet Exploreru nebo dokonce nového prohlížeče od Microsoftu a tudíž je prakticky neudržitelná podpora IE 8 i pro velké korporátní společnosti. Když jsem začal zjišťovat, co si budeme moci při psaní webových aplikací dovolit, uvědomil jsem si, že je možná na čase se rozloučit se všudypřítomným jQuery, jelikož do JavaScriptu (a souvisejících API) s podporou ES5 přibylo nemálo užitečných funkcí.
Pojďme tedy v tomto seriálu udělat restart a dát čistému Javascriptu ještě šanci.
Jak najít element v DOM postaru
Před dávnými a dávnými věky, milí vývojáři, byla modlou všech JavaScriptových vývojářů tato funkce:
document.getElementById('id');
a ta sloužila (a slouží) k nalezení elementu podle jeho id. (Pokud není nalezen žádný element, getElementById vrací hodnotu null.)
document.getElementById() má ještě několik příbuzných funkcí:
- document.getElementsByTagName()
- document.getElementsByName()
- document.getElementsByClassName()
které vrací pole elementů (popř. prázdné pole, není-li nalezeno nic), leč ty se vyskytovaly v kódu řádově méně častěji než výše zmíněná funkce document.getElementById().
Nelze zde nevzpomenout na legendární funkci document.all, zavedenou Internet Explorerem (V současné době není doporučeno ji používat a v IE11 už dokonce nefunguje). Tato funkce byla námětem mnoha učených disputací a flamewarů.
document.all['id'];
Tato funkce byla natolik oblíbená, že ji s velkým odporem implementoval i Firefox, což způsobilo kurozní situaci. Totiž test pomocí:
if (document.all) {}
se zvesela používal pro detekci Internet Exploreru, což, jak už dnes víme, je velmi, velmi ošklivé. Jenže jelikož Firefox nechtěl být detekován jako Explorer a zároveň chtěl umět document.all, musel tento test vracet vždy hodnotu false.
Pokud přesto po něčem takovém jako document.all toužíte, podobný výsledek dostanete při zavolání:
document.getElementsByTagName('*')
Jak najít element pomocí CSS selektorů v jQuery
Když se řekne jQuery, každý si představí dotazování na DOM pomocí CSS selektorů (přesto, že jQuery toho umí mnohem víc). DOM query pomocí CSS je báječný nápad, protože každý vývojář webových aplikací CSS musí znát a pracuje s ním prakticky denně.
Např:
var element = $('body div');
kde výstupem je pole elementů vyhovující zadanému dotazu. Podobně lze výraz napsat takto
var element = $('div', 'body');
kde druhým parametrem říkáme, že se dotaz se má omezit pouze na body – to bývá velmi užitečné, pokud chceme, aby naše komponenta nemohla ovlivnit ostatní. Velmi doporučuji používat.
V případě, že element není nalezen, dotaz vrací prázdné pole [].
CSS selectory v DOM
Pole všech elementů vyhovujících selectoru dostaneme takto
document.querySelectorAll('body div');
což je vlastně ekvivalentem dotazu v jQuery.
Dotaz nevrací pole, jak by se dalo po vzoru jQuery čekat, ale NodeList, což způsobí, že jej lze sice procházet jako pole (má totiž metodu item), bohužel další metody jako např.forEach nemá.
Pokud ovšem touha po polích neustává, lze to vyřešit takto:
var nodes = document.querySelectorAll('div'),
divArray = [].slice.call(nodes);
V ES 6 je to jednodušší, díky metodě Array.from, která je zatím implementována jenom ve Firefoxu:
var divArray = Array.from(div);
Pokud má být výsledkem pouze jeden element, pak použijeme jinou funkci:
document.querySelector('body div');
a výsledek je první nalezený element. Pokud dojde k situaci, že element není nalezen, document.querySelector vrací hodnotunull.
Zároveň je možno zadat skupinu selektorů (stejně jako v jQuery):
document.querySelector('#element1, #element2');
document.querySelectorAll('#element1, #element2');
pak výsledkem bude pro document.querySelector první nalezený element, pro document.querySelectorAll pak NodeList s elementy.
Zde je třeba upozornit na jeden rozdíl oproti jQuery, srovnejte:
$(''); => []
document.querySelector(''); => DOMException
document.querySelectorAll(''); => DOMException
jQuery vrací stále prázdné pole (ostatně pořád pracuje s polem elementů), zatímco querySelector v případně prázdného dotazu, vyhodí výjimku DOMException. Na to je třeba myslet a nezapomínat.
QuerySelector a querySelectorAll jsou zároveň metody, které dostal “do vínku” každý DOM element, tudíž, pokud potřebujeme vyhledávat v potomcích elementu, pak
var element = $('div', 'body');
můžeme nahradit
var element = document.querySelector('body').querySelectAll('div');
Nativní funkce jsou logicky výkonnější než funkce jQuery, což je jistě dobrý důvod k jejich použití.
Pojďme se podívat, co se stane, když CSS selektor nebude syntakticky správně:
var uglyQuery = 'div [';
$(uglyQuery);
document.querySelectorAll(uglyQuery);
pokud předpokládáte, že oba selectory skončí výjimkou, pak předpokládáte správně, jen je třeba si uvědomit, že jQuery vyhodí obecnou výjimku Error, zatímco document.querySelector pochopitelně vyhodí výjimku DOMException.
Zápis document.querySelectorAll je prostě dlouhý a nebudu se vůbec divit, bude-li se zkracovat. Je to funkce jako každá jiná, řekneme si, takže ji jen stačí přiřadit
var q = document.querySelectorAll;
ale ouha, dojde k výjimce, a to k výjimce Illegal invocation, která se nevidí každý den.
Pro moderní prohlížeče a IE9+ je řešení docela elegantní:
var q = document.querySelector.bind(document);
pro prohlížeče nepodporující metodu bind pak nezbývá než udělat toto:
var q = function(q) { return document.querySelector(q); };
ClassList
Milým objevem (pro mne) je, že pro operace s třídami jako jako je addClass, removeClass, toggleClass nepotřebuji jQuery a taktéž na starý způsob s nastavováním řetězce classNameuž můžu zapomenout.
Nejdříve postaru:
// addClass
element.className += ' active';
// removeClass
element.className = element.className.replace('active', '').trim();
Funkci toggle si doplní laskavý čtenář sám, já už to, doufám, nikdy nebudu muset psát.
V jQuery to dokážeme o poznání elegantněji
$(element).addClass('active');
$(element).removeClass('active');
$(element).toggleClass('active');
$(element).hasClass('active');
Od IE 10 lze použít toto:
element.classList.add('active');
element.classList.remove('active');
element.classList.toggle('active');
element.classList.contains('active');
Na první pohled by se mohlo zdát, že classList obsahuje pole, ale Array takové metody jako toggle nemá. Je to tím, že classList vrací DOMTokenList, datový typ pro hodnoty v DOM, oddělované mezerou.
Perlička na závěr
Při ověřovaní informací výše uvedených, jsem narazil na funkci elementu s podivným názvem insertAdjacentHTML. Domníval jsem se že jde o novinku, a tak mě překvapilo, že je implementována v IE4.
Druhým překvapením bylo, že by měla být o poznání výkonnější než nastavení vlastnosti innerHTML.
Použít se dá místo:
$(el).after(html);
a to takto:
el.insertAdjacentHTML('afterend', html);
Inu člověk se učí pořád.
Přehled komentářů