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

  19. Wielkie dzięki, od paru dni szukałem po necie żeby ktoś tak fajnie to wszystko wytłumaczył.

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ę.