Relacje między elementami
Wiemy już, że elementy na stronie tworzą hierarchiczne drzewo.
Aby operować na takich obiektach, musimy dobrze opanować sztukę "spacerowania" po nich.
Możemy je oczywiście wybierać za pomocą querySelector czy querySelectorAll (i podobnych), ale czasami to za mało.
Każdy element na stronie tworzy tak zwany węzeł. Takimi węzłami są nie tylko elementy, ale także tekst w nich zawarty.
Relacje między węzłami
Przeanalizujmy przykładowy kawałek html:
<div class="test-cnt">
<p id="text">
Mała
<strong style="color:red">Ala</strong>
miała
<span style="color:blue">kota</span>
</p>
</div>
Składa się on z węzłów. Węzłami są kawałki tekstu, ale i elementy, z których złożony jest html. Znając ich położenie, w łatwy sposób możemy się po nich poruszać korzystając z właściwości, które udostępnia nam każdy element.
const p = document.querySelector("p#text");
//właściwości pobierające elementy html
p.parentElement //wskazuje na nadrzędny element - div.test-cnt
p.firstElementChild //pierwszy dziecko będące elementem
p.lastElementChild //ostatnie dziecko będące elementem
p.children //[strong, span] - kolekcja dzieci elementu
p.children[0] //pierwsze dziecko - to samo co firstElementChild
p.nextElementSibling //następny element z rodzeństwa
p.previousElementSibling //poprzedni element z rodzeństwa
//właściwości pobierające węzły
p.parentNode //wskazuje na nadrzędny węzeł
p.firstChild //pierwszy node - w naszym przypadku to tekst "Mała "
p.lastChild //ostatni node - "" - html jest sformatowany, wiec ostatnim nodem jest znak nowej linii
p.childNodes //kolekcja wszystkich dzieci nodów - nie tylko elementów [text, strong, text, span] -
p.childNodes[0] //"Mała"
p.nextSibling //następny węzeł z rodzeństwa
p.previousSibling //poprzedni węzeł z rodzeństwa
Mała Ala miała kota
W większości przypadków będzie nas interesować odwoływanie się do elementów html, dlatego głównymi właściwościami, które nas interesują są:
element.parentElement | rodzic elementu lub null |
---|---|
element.nextElementSibling | następny element (brat) lub null |
element.previousElementSibling | poprzedni element (brat) lub null |
element.children | dzieci elementu lub pusta kolekcja |
element.firstElementChild element.children[0] |
pierwsze dziecko elementu lub null |
element.lastElementChild element.children[element.children.length-1] |
ostatnie dziecko elementu lub null |
closest(), contains()
Metoda element.closest("selektor-css") idąc w górę drzewa zwraca najbliższy element który pasuje do selektora lub null
jeżeli nie znajdzie żadnego pasującego elementu:
<div class="module">
<div class="module-content">
<div>
<button class="button">Kliknij</button>
</div>
</div>
</div>
const btn = document.querySelector(".button")
btn.addEventListener("click", () => {
const module = btn.parentElement.parentElement.parentElement;
//lub
const module = btn.closest(".module");
});
Pisząc nasze skrypty powinniśmy starać się robić to w taki sposób, by były jak najbardziej uniwersalne. Sztywne poruszanie się po drzewie nie zawsze będzie najlepszym rozwiązaniem. Struktura HTML może się zmienić (np. wymagać będzie tego stylowanie), dlatego jeżeli dana sytuacja pozwala, zamiast wielu parentElement
czy podobnych, o wiele lepiej użyć jednego closest()
by złapać rodzica, i ewentualnie później wyszukiwać w takim elemencie za pomocą querySelector()
.
<div class="module">
<h2>lorem ipsum</h2>
<div>
<div>
<div>
<button>klik</button>
</div>
</div>
</div>
<footer></footer>
</div>
//zamiast
const btn = document.querySelector("button");
const h2 = btn.parentElement.parentElement.parentElement.previousElementSibling;
const footer = btn.parentElement.parentElement.parentElement.nextElementSibling;
//o wiele lepiej
const btn = document.querySelector("button");
const module = btn.closest(".module");
const h2 = module.querySelector("h2");
const footer = module.querySelector("footer");
Trening czyni mistrza
Jeżeli chcesz sobie potrenować zdobytą wiedzę, zadania znajdują się w repozytorium pod adresem: https://github.com/kartofelek007/zadania