Niezwykle istotną sprawą przy tworzeniu skryptów jest możliwość łatwego poruszania się po drzewie dokumentu - w MooTools mamy kilka metod, które pozwalają nam na dostęp do różnych elementów względem innych elementów. Dodatkowo zapoznamy się bliżej z funkcją $$, która pozwala na selekcję kilku elementów naraz według określonych parametrów.

Dolary

Jak wiemy funkcja $ pozwala przede wszystkim na selekcję pojedynczego elementu według jego atrybutu id. W wypadku funkcji $$ możemy wyselekcjonować całe grupy elementów. W podstawowej wersji możemy dokonywać selekcji według tagów natomiast po dodaniu obsługi selektorów do frameworka możemy korzystać także z selektorów CSS. Zatem aby uzyskać dostęp do wszystkich obrazków na stronie zapiszemy:

$$('img');

Aby wybrać tylko obrazki posiadające klasę image:

$$('img.image');

Dodatkowo możemy stworzyć grupę elementów złożoną z kilku typów elementów - przykładowo aby wybrać wszystkie obrazki ze strony i linki z klasą link, zapisujemy:

$$('img', 'a.link');

Zatem jako kolejne argumenty możemy podawać kolejne selektory elementów. Dodatkowo jeżeli musimy wykonać jakąś operację na danym elemencie do którego mamy już uchwyt w postaci zmiennej i grupie innych elementów, które należy dopiero wyselekcjonować zapiszemy:

var el = $('element');
 
// fragment kodu
 
$$(el, 'img');

Powyższy kod spowoduje stworzenie tablicy wszystkich obrazków ze strony i elementu posiadającego id "element". Jest to zdecydowane ułatwienie - nie musimy do kolekcji elementów dodawać w dalszym kodzie nowej pozycji lub tworzyć jakichś cech wspólnych dla danych elementów tylko po to by ułatwić sobie później selekcję w JavaScript.

Możliwości funkcji $$ są ogromne, ale prawdziwy ich urok poznamy dopiero przy omawianiu selektorów w dalszej części kursu.

Dolary inaczej

Swego rodzaju odpowiednikami funkcji $ i $$ są metody getElement, getElements oraz getElementById. Różnica polega na tym, że pozwalają na selekcję tylko jednej grupy elementów - zatem zapis taki jak:

$$('img', 'a.link');

Jest niemożliwy. Ale metody te mają inną zaletę - pozwalają na selekcję w obrębie danego elementu. Zatem zamiast stosować selektor:

$$('#testowy a.link');

Możemy wykorzystać zapis:

var el = $('testowy');
el.getElements('a.link');

Oczywiście zapis jest dłuższy, ale za to pozwala na stosowanie prostszych selektorów, a także wygląda w kodzie bardziej logicznie przy pętlach wykonujących selekcję elementów potomnych z kilku elementów. Metoda getElement różni się od getElements tym, że zwraca pierwszy element z całej kolekcji. Zatem jeżeli interesowałby nas tylko pierwszy link z klasą link w elemencie posiadającym id "testowy" zapiszemy:

var el = $('testowy');
el.getElement('a.link');

Jeżeli chodzi o metodę getElementById to powstała ona po to by uzupełnić funkcjonalność natywnej metody obiektu document związanej z DOM - getElementById pozwala ograniczyć zakres poszukiwań do danego elementu - wydawałoby się, że istnienie takiej metody jest mało sensowne, ponieważ atrybut id powinien być unikalny, ale metoda ta jest przydatna w sytuacji, gdzie musimy stwierdzić czy element o danym id jest elementem potomnym innego elementu:

var el = $('testowy');
var result = el.getElementById('link');

Zmienna result będzie zawierała uchwyt do elementu posiadającego id "link", jeżeli jest on potomkiem elementu posiadającego id "testowy" - w innym wypadku otrzymamy wartość null. Oczywiście można to też zbadać inaczej:

var result = $$('#testowy #link'); 

Jeżeli tablica result jest pusta to element "link" nie jest potomkiem elementu "testowy" - znów wszystko tak naprawdę dotyczy tego jak bardzo złożonych selektorów chcemy używać.

Dla podsumowania tej części wpisu przykład prezentujący różne rodzaje selekcji elementów wraz z użyciem funkcji i metod:

PRZYKŁAD 1

Warto zwrócić uwagę na równoważne zapisy oraz te zapisy, które nie zwracają żadnych elementów.

Bądź punktem odniesienia

Teraz chciałbym omówić metody, które pozwalają dokonywać selekcji elementów względem innego elementu w zakresie elementów sąsiednich, nadrzędnych i potomnych.

Na początek warto zapamiętać sobie trzy najważniejsze cechy wspólne wszystkich metod, które za chwilę omówię - jako argument mogą one opcjonalnie przyjmować typ elementu - zatem możemy dokładnie zdefiniować czego szukamy, zwłaszcza w momencie gdy mamy do dyspozycji rozbudowane selektory CSS. Druga cecha to fakt, że dla wszystkich rodzajów operacji istnieją zawsze dwa rodzaje selekcji - analogiczne do funkcji $ i $$. Zatem jedna metoda dokonuje selekcji pojedynczego elementu, a druga zwraca kolekcję elementów. Trzecia cecha - jeżeli element jaki chcieliśmy uzyskać nie istnieje to każda z tych metod zwraca wartość null.

Zacznijmy od wykrywania elementów nadrzędnych - do dyspozycji mamy metody getParent i getParents - już same nazwy mówią, która metoda jest odpowiednikiem funkcji $, a która odpowiednikiem funkcji $$. Zatem aby wykryć element nadrzędny wystarczy zapisać:

element.getParent();

Mając strukturę:

<div>
    <a href="http://blog.dziudek.pl">Link</a>
</div>

I przyjmując, że zmienna element jest uchwytem do linka, uzyskalibyśmy uchwyt do elementu div.

Możemy też stworzyć taką strukturę elementów jak poniższa:

<div>
    <ul>
        <li><a href="http://blog.dziudek.pl">Link 1</a></li>
        <li><a href="http://miniblog.dziudek.pl">Link 2</a></li>
    </ul>
</div>

Aby uzyskać uchwyty do elementów li, ul i div wystarczy zapisać:

element.getParents();

Gdzie zmienna element odnosi się do pierwszego lub drugiego linka.

To były podstawowe możliwości tych metod - a gdybyśmy chcieli szybko uzyskać uchwyt do elementu div z poziomu linka ?

W "starym" MooTools 1.11 musielibyśmy zapisać:

element.getParent().getParent().getParent();

A w naszym wypadku możemy zapisać:

element.getParents()[2];

Lub:

element.getParent('div');

Nie będę ukrywał, że drugi zapis jest o wiele bardziej elastyczny - przede wszystkim mamy pewność, że uzyskamy uchwyt do pierwszego nadrzędnego elementu typu div - możliwości jakie daje ten jeden niepozorny parametr we wszystkich funkcjach tego typu proszę przeanalizować samemu - na pewno w wielu wypadkach ułatwiają życie oraz często skracają kod skryptu.

Oczywiście w naszym wypadku zapis:

element.getParent('div');

Jest równoznaczny z zapisem:

element.getParents('div'); 

Ale w wypadku bardziej rozbudowanej witryny drugi zapis może zwrócić więcej elementów nadrzędnych typu div.

Pora na dzieci

Wiemy już jak odnaleźć rodziców naszego elementu - a co z dziećmi (potomkami) ? Istnieje metoda getChildren, która wyjątkowo nie ma odpowiednika getChild - w zamian mamy metody getFirst oraz getLast.

Metoda getChildren pozwala nam uzyskać kolekcję wszystkich elementów potomnych danego elementu lub tylko tych, które określono w podanym jako argument selektorze. Należy pamiętać, że elementy potomne rozumiemy jako te, które znajdują się bezpośrednio w danym elemencie. Skorzystajmy ze znanej już struktury elementów:

<div>
    <ul>
        <li><a href="http://blog.dziudek.pl">Link 1</a></li>
        <li><a href="http://miniblog.dziudek.pl">Link 2</a></li>
    </ul>
</div>

W tym wypadku element div ma tylko jeden element potomny - listę nieuporządkowaną. I to ona będzie jedynym elementem kolekcji zwracanej przez:

element.getChildren();

Gdzie element to oczywiście uchwyt do naszego jedynego diva. Zatem zapis:

element.getChildren('li');

Zwróci nam wartość null. Gdybyśmy teraz zmienną element zdefiniowali jako:

var element = $$('ul')[0];

I wykorzystali metody getFirst i getLast:

element.getFirst();
element.getLast();

To uzyskalibyśmy dostęp odpowiednio do pierwszej i ostatniej pozycji listy nieuporządkowanej.

Zapis:

element.getFirst().getFirst('b');
element.getLast().getFirst('i');

Zwróci nam oczywiście wartości null, ponieważ elementy listy nie zawierają elementów kursywy i pogrubienia.

W poniższym przykładzie prezentuję kilka metod selekcji z użyciem poznanych dotychczas metod związanych z elementami nadrzędnymi i potomnymi:

PRZYKŁAD 2

Warto zwrócić uwagę na odwołanie do tablic elementów oraz auto-iterację.

Zostali sąsiedzi

Wiemy jak dokonać selekcji elementów położonych o poziom wyżej i niżej - istnieją też metody do selekcji elementów na tym samym poziomie - jedną z nich - getNext już poznaliśmy przy okazji omawiania zdarzeń elementów. Pozostały nam do omówienia jeszcze metody getAllNext, getPrevious oraz getAllPrevious.

Weźmy pod uwagę następującą strukturę elementów:

<div>
    <p>Tekst 1</p>
    <img src="obrazek.png" alt="obrazek" />
    <p>Tekst 2</p>
    <p>Tekst 3</p>
    <ul>
        <li>Pozycja 1</li>
        <li>Pozycja 2</li>
    </ul>
</div>

Gdybyśmy przyjęli, że naszym punktem odniesienia - zmienną element jest drugi paragraf tekstu to metoda:

element.getNext();

Zwróciłaby nam trzeci paragraf. Ta sama metoda z podanym argumentem:

element.getNext('ul');

Zwróci nam uchwyt do listy nieuporządkowanej. A oba te element (trzeci paragraf i listę nieuporządkowaną) naraz zwróci metoda:

element.getAllNext();

Z metodą getPrevious jest dokładnie na odwrót (działa "w górę"), zapis:

element.getPrevious();

Zwróci nam uchwyt do obrazka, a zapis:

element.getPrevious('p');

Zwróci nam pierwszy paragraf. No i oczywiście zapis :

element.getAllPrevious();

Zwróci nam oba te elementy (obrazek i pierwszy paragraf tekstu) naraz.

Celowo nie rozwodziłem się nad tymi metodami, ponieważ są one w swoich założeniach łudząco podobne do poznanych już metod - operują jedynie na innych poziomach elementów z otoczenia naszego punktu odniesienia jakim jest element wskazywany przez zmienną element.

Kilka przykładów selekcji umieściłem w poniższym przykładzie:

PRZYKŁAD 3

W ramach treningu

Proponuję przygotować zestaw odpowiedników poznanych metod działających jako samodzielne funkcje:

  • getParent - $P,
  • getParents - $PS,
  • getChildren - $C

Należy pamiętać by uwzględnić fakt, że drugi argument (scope) jest w tych funkcjach jak najbardziej pożądany (no może poza funkcją getChildren). Do tego proponuję napisać funkcje:

  • $I - selekcjonująca obrazki z dokumentu (opcjonalnie argument ograniczający zakres selekcji),
  • $F -selekcjonująca formularze z dokumentu (opcjonalnie argument ograniczający zakres selekcji)

Podsumowanie

Wiemy już jak poruszać się po drzewie dokumentu, a nawet można by powiedzieć, że potrafimy po nim swobodnie skakać :) W następnej części poświęconej elementom dokumentu zajmiemy się atrybutami elementu i nowościami jakie pojawiły się w MooTools 1.2 w zakresie przechowywania informacji w elementach.

Komentarze do wpisu "MooTools 1.2 - elementy strony cz. 1":

1. Bigismall napisał(a):
04 września 2008, 07:32:33

Jeśli o mnie chodzi, to $$() jest powodem dla którego zacząłem uzywać MooTools.

Świetny wpis. Idealny do zachęcenia ludzi do zapoznania się z tą biblioteką.

Dodaj komentarz:

Textile Lite włączony ( szczegółowy opis znaczników ):
*strong* | # lista numerowana | * lista wypunktowana | _em_ | __italic__ | "link":http:// | bq. cytat.