JavaScript Restart – QuerySelector

Setkávám se často s vývojáři jejichž první úvaha nad implementací začíná napsáním “$”. jQuery je všudypřítomné, a pro tyto vývojáře je překvapení, že se dá psát bez něj.

Seriál: JavaScript Restart (4 díly)

  1. JavaScript Restart – QuerySelector 11.2.2015
  2. JavaScript Restart – Hurá na pole 23.2.2015
  3. JavaScript Restart – Neidentifikovatelný létající objekt 9.3.2015
  4. JavaScript Restart – Restartováno 27.3.2015

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.

Pracuje jako vývojář webových aplikací ve společnosti TopMonks, s.r.o. a specializuje se na JavaScript, AngularJS a EmberJS, hlavně na vývoj uživatelských rozhraní. Je členem kapely Rezatý Rakety. Když nehraje ani neprogramuje, inhaluje výpary při lepení plastikových modelů.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 15

Přehled komentářů

DavidGrudl Funkce jQuery nevrací pole
Miroslav Juhos Re: Funkce jQuery nevrací pole
Daniel Re: Funkce jQuery nevrací pole
Jakub Vrána Další nepřesnosti
steida Re: Funkce jQuery nevrací pole
dherbolt Rozdíl mezi objektem jQuery, NodeList (statický) a HTMLCollection
smokie.mt Neviem, neviem
DavidGrudl Re: Neviem, neviem
Jakub Re: Neviem, neviem
Lemming Re: Neviem, neviem
Martin Re: Neviem, neviem
helb You might not need jQuery…
xxar3s Re: You might not need jQuery…
xerno Sizzle
Dash jQuery 2
Zdroj: https://www.zdrojak.cz/?p=14308