Kupujesz wysyłkowo lampkę odstraszającą owady, okazuje się, że żarówka jest spalona. Zamawiasz buty przez internet, za ciasne. Wreszcie rozpakowujesz paczkę, w której czeka wymarzy robot kuchenny, który będzie pasował pod kolor kuchni, dostajesz zupełnie inny kolor. Ręce opadają. Te opadają też czasem przy walce z przeciwnościami podczas programowania. Dziś pokażę Ci jedną z takich kłód rzucanych pod nogi, ale zastrzegam: nie jest to złośliwość twórców przeglądarek, ani też ich przeoczenie.
Zacznijmy od przykładu nawiązującego do tytułu.
<body>
<ul id="element1">
<li></li>
<li></li>
<li></li>
</ul>
</body>
Spróbujmy teraz pobrać z powyższej struktury bezpośrednie dzieci #element1, które są tagami LI.
var li = document.getElementById("element1").querySelectorAll(">li");
I co otrzymałeś próbując wyświetlić wyniki z pomocą console.log?
Dlaczego tak się stało, o tym dalej.
Zmieńmy trochę kod JavaScript przy niezmienionym kodzie HTML:
var li = document.getElementById("element1").querySelectorAll("li");
A teraz jaki wynik otrzymałeś? Pewnie tablicę trzyelementową. Dlaczego więc dla selektora ogólnego metoda zwraca poprawny wynik, a dla selektora bezpośrednich dzieci zwraca błąd?
Spróbujmy to rozjaśnić następującym kodem:
<body>
<div>
<p id="paragraf">
<a href="#">link 1</a>
</p>
</div>
<div>
<a href="#">link 2</a>
</div>
</body>
var a = document.getElementById("paragraf").querySelectorAll("div a");
Jeśli sprawdzisz co otrzymałeś, to pewnie sobie pomyślisz, że przykład zamiast rozjaśnić sytuację, to jeszcze bardziej ją zaciemnił. A otrzymałeś pewnie jednoelementową tablicę z tagiem A.
Dlaczego?
Przecież w takim przypadku powinniśmy otrzymać pustą tablicę, bowiem element #paragraf nie ma dzieci DIV, a ten dzieci A. Dzieje się tak, ponieważ selektor zadziałał na całym dokumencie, a potem spośród elementów spełniających jego "warunek" odfiltrował elementy, które są dziećmi #paragraf. Czyli w pierwszym "kroku" metoda otrzymała 2 tagi A, a następnie wybrała spośród nich tylko te, które są dziećmi elementu P (czyli tylko jeden element A).
A co z tytułowymi selektorami?
Wróćmy więc do selektora >, zresztą analogiczna sytuacja jest z selektorem + (bezpośredniego sąsiada).
Dlaczego nie działa tak jak tego oczekujemy? Biorąc pod uwagę powyżej opisany sposób funkcjonowania, metoda najpierw wyszukałaby bezpośrednie dzieci dokumentu spełniające warunek selektora, a spośród nich odfiltrowałaby bezpośrednie dzieci #element1. Czy jest możliwe, aby elementy były jednocześnie bezpośrednimi dziećmi dokumentu oraz bezpośrednimi dziećmi #element1? A czy jest możliwe, aby w przypadku selektora +, element był bezpośrednim sąsiadem dokumentu i bezpośrednim sąsiadem #element1?
Teraz pewnie już znasz odpowiedź.
Tak przy okazji - sytuacja jest analogiczna w przypadku metody querySelector.
A czy jest jakieś rozwiązanie? Tak!
Pierwsze z nich polega na dodaniu do elementu, na którym wykonujemy metodę querySelector(All) atrybutu id, a następnie uwzględnienie w selektorze tego atrybutu:
var li = document.getElementById("element1").querySelectorAll("#element1>li");
Trochę to dziwne, ale działa.
A drugie? Drugie polega na dodaniu do selektora pseudoklasy :scope:
var li = document.getElementById("element1").querySelectorAll(":scope>li");
Pseudoklasa :scope powoduje przeniesienie działania metody z dokumentu do elementu, na którym metoda jest wywoływana.
Głowa do góry! Nie zawsze to czego nie chcemy, działa przeciwko nam. Jak to mówią, nie ma tego złego.
Przydatne linki:
"Hello dolar", czyli po co mi jQuery?
Metoda document.querySelectorAll
Metoda document.querySelector
Metoda element querySelectorAll
Metoda element.querySelector