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");

Wszelkie prawa zastrzeżone. Jeżeli chcesz używać jakiejś części tego kursu, skontaktuj się z autorem.
Aha - i ta strona korzysta z ciasteczek.