Perfection or Vanity

Project: Terminated

Blog nie jest już dalej prowadzony ani aktualizowany. Mimo tego, wpisy i komentarze są dalej dostępne. Możesz przeczytać pożegnalny wpis albo przejść do archiwum.

Wcześniej powiedziałem, że DOM można, a nawet powinno się, obrazować jako drzewo. DOM jako API udostępnia nam cały zestaw metod odnajdywania interesującego nas elementu w gałęziach tego drzewa.

Możemy wyszukać zestaw elementów i za pomocą paru dodatkowych sztuczek odnaleźć ten jedyny. Możemy także korzystać z relacji elementu aktywnego z jego rodzicami, dziećmi jak i rodzeństem - słownictwo bardzo rodzinne, ale dokładnie z tych nazw w języku angielskim korzystają nazwy tych metod.

Mała uwaga: nazwy metod piszemy stylem wielbłądzim, pozostawiając pierwszą literę małą.


Całkowitą podstawą jest getElementById. Po wywołaniu

  1. document.getElementById("content")

otrzymamy element posiadający id="content", jeśli taki znajduje się na stronie. Warto przed przystąpieniem do operacji na uchwycie sprawdzić czy znajduje się on w dokumencie.

  1. var handle = document.getElementById("content");
  2. if (handle) {
  3. } else {
  4. return false;
  5. }

W innym przypadku, biorąc tylko pod uwagę interakcję użytkownik - strona, Internet Explorer wywali okienko z wielką złą czerwoną ikoną i mało zachęcającym komunikatem.

No dobrze, powiesz, ale przecież nie będę pisał w każdym znaczniku jakiegoś id, żeby potem móc operować na nim w JavaScripcie. Oczywiście, że nie - getElementById to wierzchołek góry lodowej. Dalej mamy getElementsByTagName. Metoda ta pobierze do tablicy wszystkie elementy znajdujące się w drzewku pod elementem z którego ją wywołaliśmy.

  1. document.getElementsByTagName("p")

zwróci wszystkie akapity na stronie włożone do tablicy. Skorzystanie z

  1. document.getElementById("content").getElementsByTagName("p")

przy założeniu, że w dokumencie mamy jakiś tag z id="content" pozwoli pobrać wszystkie akapity w nim zawarte jak i w jego potomkach. Ilustruje to graf:

Graf ilustrujący getElementById i getElementsByTagName

Do tablicy możemy odwoływać się korzystając z numeru indeksu:

  1. getElementsByTagName("p")[0]

Zwróci nam to pierwszy akapit (w tablicach indeks zaczyna się od 0). Jest to też sposób na pobranie uchwytu do elementu, który występuje tylko raz (jeśli wiemy to na pewno) w danej gałęzi, bo nie ma czegoś takiego jak

  1. getElementByTagName("p")

Oczywiście mając tablicę możemy wykonać na niej operacje, najszybciej korzystając z pętli:

  1. for (var i = 0; i < paragraphs.length; i++) { … instrukcje … }

W przykładzie i to zmienna licznika tablicy (zwiększająca się o jeden w cyklu, o czym mówi zapis i++), paragraphs jest na przykład zmienną przechowującą wynik naszego wcześniejszego getElementsByTagName("p"), a zapis .length odwołuje się do jej wielkości. Cała linijka znaczy tyle, że pętla będzie się wykonywać tyle razy ile mamy akapitów p w paragraphs.

Odwołanie do elementu w pętli jest podobne jak w poprzednim przykładzie, tylko zamiast podawać gotową liczbę, wstawiamy zmienną i:

  1. paragraphs[i]

Aby pobrać wszystkie elementy z aktualnej gałęzi (w przypadku document będą to wszystkie elementy dokumentu) należy użyć znaku gwiazdki:

  1. getElementsByTagName("*")

Teraz trochę o relacjach. Będąc w określonym miejscu w DOM możemy odnieść się do elementu powyżej nas - rodzica. Służy do tego parentNode.

Graf ilustrujący parentNode

Gdy jesteśmy zmuszeni odwołać się do wszystkich elementów poziom niżej danego węzła, używamy childNodes. Warto sprawdzić czy element posiada jakieś childNodes stosując warunek z hasChildNodes. Jeśli okaże się, że istnieje jest tylko jeden element, childNodes nadal zwraca tablicę, do której możemy odwołać się jak poprzednio - childNodes[0].

Graf ilustrujący childNodes

DOM udostępnia także łatwe metody na pobranie pierwszego - firstChild - i ostatniego - lastChild - elementu niżej w gałęzi.

Graf ilustrujący firstChild, lastChild

Na koniec zostają metody i zwracające element po - nextSibling - i przed - previousSibling - elementem z którego je wywołujemy. W ten sposób można się łatwo przełączać między jednopoziomowymi węzłami, nawet jeśli mają pod sobą dalsze rozgałęzienia.

Graf ilustrujący nextSibling, previousSibling

Korzystając z tych relacji jedynie dostajemy „uchwyt” za pomocą którego możemy modyfikować atrybuty aktualnego elementu. Samego elementu podmenić nie możemy - o metodach wstawiania, podmiany oraz usuwania elementów drzewa opowiem wkrótce. W końcu także dojdziemy do przykładów z życia wziętych, aby nie zanudzić się podręcznikowymi formułkami.

Dalej →

Informacje i hiperłącza

Blog o projektowaniu zgodnych ze standardami stron internetowych.

Praktyczne przykłady, sztuczki CSS, sposoby obchodzenia błędów przeglądarek, lekki i nieinwazyjny JavaScript, użyteczny design, dostępność i skrypty użytkownika.

RSS

Informacje o wpisie

Napisał riddle 08 marca 2006 o 16:50

Kategorie: JavaScript & DOM, Standardy sieciowe

Dodaj do:

Wpisy archiwalne

Archiwum miesięczne

Dzięki!

Dodaj bloga do Technorati Favorites Dodaj bloga do Del.icio.us Blog należy do sieci 10przykazań.com

  1. To kiedy następna część? :-)

    A propos pętli for (var i = 0; i < paragraphs.length; i++) { … instrukcje … } - w JS nie ma konstrukcji foreach, tylko trzeba jak w Delphi < 9 protezy stosować?

  2. A po co instrukcja foreach... napisanie for(...) to tylko kilka sekund więcej, a masz większa kontrolę nad pętlą.

  3. @Nazgul, zapominasz o takim słówku: *wybór*. Potrzebujesz mieć większą kontrolę, użyj for. Wolisz coś zrobić szybko i w łatwy sposób - foreach.

    @Piotr, zaznacz dokładnie o co chodzi w getElementByTagName, bo założe się, że 90% osób, która nie wie o co chodzi, nic tam nie wyczyta.

  4. Do przeszukiwania tego co zwraca getElementsbyTagName wolę uzywać metody item. Z tablicami miałem jakieś problemy.

  5. getElementsByTagName("*") - działa dopiero od IE6 jeśli się nie mylę

    for (var i = 0; i < paragraphs.length; i++) { paragraphs[i].blah }
    nieco wygodniejsza (czasem) kontrukcja:
    for (var i = 0, p; i < p=paragraphs[i]; i++) { p.blah }

    warto też zainteresować się XPath, do którego świetny wstęp napsał niejaki Umarł Jutro na Webhelpie: http://forum.webhelp.pl/viewtopic.php?p=632950#632950
    Jak to opisał sam autor: "tak po krótce to zamiast getElementsByCośTam, które w porównaniu z XPath jest jak stare wrotki przy najnowszym Jaguarze, używasz formuły XPath do wyłuskania z drzewa DOM interesujących cię elementów".

  6. Więcej! ;-)

    PS. te grafy to "ręcznie" robisz? :)

  7. Już w którejś notce wcześniej Riddle wspomniał (właściwie w komentarzu do notki :) ), że używa ręcznie tworzonych grafów. Chyba, ze znalazł sobie jakieś narzędzie :)

  8. W JS zamiast foreach jest odmienna konstrukcja for:
    var a=new Array(1, 2, 3, 4, 5);
    for (var i in a) alert(i)

  9. Pytanie tochę nie na temat - @Riddle: czego Ty używasz do robienia takich ładnych schematów? Photoshop? :)

  10. Prawdziwe geeki do rysowania grafów używają wyłącznie rdf+gss+svg :-)

    radziel: zapewniam, że dasz rady w zarówno w Adobe Photoshop, jak i Corel Photo-Paint, Corel Paint Shop Pro, GIMP, Pixel, Adobe Fireworks i wielu wielu innych, które mają zaimplementowanego blura, gradienty i rysowanie kształtów.

  11. Pisz, Riddle, pisz - podobnych materiałów (sensownych) w polskim Internecie niewiele jest, więc trzeba nam czegoś takiego.

  12. nareszcie ktoś to po ludzku napisał
    przyda mi się, dzięki !

  13. No. Wreszcie fajny tekst, zamiast geekowatych rozważań ;-)

  14. Tego mi było trzeba ;) Z niecierpliwością czekam na następną wersję. Nawet nie wiesz jak mi pomogłeś :) Oby więcej takich porad.
    PS.:Teraz już wiem jak zrobiłeś, że po najechaniu na paragraf podkreślają się dotted/dashed wszystkie linki znajdujące się w nim.

  15. Warto chyba wspomnieć o różnicach między przeglądarkami - dotyczą one przede wszystkim nextSibling i previousSibling, a także długości tablicy childNodes. IE nie uznaje białych znaków między elementami jako węzłów, natomiast dla Geckowatych i Opery są to kolejne węzły. Przetestuj używając alert(document.body.childNodes.length) na identycznym dokumencie. Z tym wiąze się problem: dla IE element.nextSibling będzie tym, czego się spodziewamy, czyli kolejnym elementem HTML w kodzie, natomiast w pozostałych przeglądarkach może okazać się że element.nextSibling to pusty znak i skrypt nie zadziała tak jak oczekiwaliśmy.

  16. [Jack-Web]: „PS.:Teraz już wiem jak zrobiłeś, że po najechaniu na paragraf podkreślają się dotted/dashed wszystkie linki znajdujące się w nim.”

    do tego akurat wystarczy sam CSS :)
    div.wpis:hover>a {border-bottom: 1px dashed #aaa;}

  17. mootools - element.js

    Przed przejściem do lektury na temat pliku element.js polecam osobom, które o DOM maja małe pojęcie przeczytać trochę materiałów na ten temat. Osobiście polecam ten artykuł o obiektach DOM oraz wpisy Riddle'a na ten temat:

    Document Object[...]

  18. Wielkie dzięki! JS używam bardzo rzadko, więc mam z nim pewne problemy. Dziś musiałem zsumować pola w formularzu. Gdyby nie getElementById to bym się zarżnął (bo ze względu na współpracę z php atrybut name tych pól zawiera nawiasy kwadratowe, których JS nie chciał łyknąć. A tymczasem z innej przyczyny miałem już dodane do wszystkich pól atrybuty id :D

Dodaj komentarz

Do formatowania komentarzy używaj Textile (HTML nie działa). Szczególnie jeśli wklejasz większe fragmenty kodu. W razie niepewności użyj podglądu komentarza.

Wypowiedzi obraźliwe, infantylne oraz nie na temat będą moderowane – pisząc postaraj się zwiększyć wartość dyskusji.

Komentarze nie służą do wysyłania wiadomości albo informowania o błędach, itd. Chcesz coś mi napisać – skontaktuj się.