W kolejnej części kursu poświęconej elementom strony, zajmiemy się dynamicznym tworzeniem elementów, zmienianiem ich atrybutów oraz zapoznamy się z zupełnie nową funkcjonalnością klasy Element - możliwością przechowywania informacji w obiektach tej klasy.

Tworzenie elementów

Prędzej czy później podczas tworzenia bardziej złożonego skryptu JavaScript zachodzi potrzeba stworzenia zupełnie nowego elementu "w locie". W MooTools wystarczy stworzyć nowy obiekt klasy Element z podanym jednym argumentem - typem elementu:

var nowyDiv = new Element('div');

Jest to najprostszy przykład użycia konstruktora elementów. Ma on jednak o wiele bardziej rozbudowane możliwości - możemy określić zawartość poszczególnych atrybutów danego elementu - dokonujemy tego dzięki obiektowi podanemu jaki drugi argument konstruktora:

var nowyDiv = new Element('div',{
    'class':'testowy', 
    'id':'pierwszy'
});

Dodatkowo możemy określić styl elementu w obiekcie style:

var nowyDiv = new Element('div',{
    'class':'testowy', 
    'id':'pierwszy', 
    'style' : {
        'background': '#EEE',
        'color': '#777'
    }
});

Istnieją jeszcze trzy parametry do określenia - zawartość elementu możemy określić poprzez właściwości text lub html - różnica oczywiście polega na tym, że z pierwszej z nich korzystamy dodając tylko tekst, a z drugiej podczas dodawania tekstu z kodem (X)HTML:

var nowyDiv = new Element('div',{
    'class':'testowy', 
    'id':'pierwszy', 
    'style' : {
        'background': '#EEE',
        'color': '#777'
    },
    'text': 'przykładowy tekst'
});
var nowyDiv = new Element('div',{
    'class':'testowy', 
    'id':'pierwszy', 
    'style' : {
        'background': '#EEE',
        'color': '#777'
    },
    'html': '<strong>przykładowy pogrubiony tekst</strong>'
});

Ostatnia właściwość to events - pozwala od razu określić zdarzenia elementu:

var nowyDiv = new Element('div',{
    'class':'testowy', 
    'id':'pierwszy', 
    'style' : {
        'background': '#EEE',
        'color': '#777'
    },
    'text': 'przykładowy tekst',
    'events': {
        'click': function(){
            // kod zdarzenia onclick
        },
        'mouseenter': function(){
            // kod zdarzenia onmouseenter
        },
        'mouseleave': function(){
            // kod zdarzenia onmouseleave
        }
    }
});

Jak widać można całkiem spory kawałek kodu wygenerować dla stworzenia pojedynczego elementu z zawartością i zdarzeniami.

Konstruowaniem nowych elementów zajmiemy się poważniej przy okazji następnej części poświęconej elementom strony i m.in. metodzie inject. Warto jednak zwrócić uwagę na pewne podobieństwo konstruktora elementu do metody set.

Set i get

Każdemu obiektowi klasy Element możemy określić wartości poszczególnych cech za pomocą metody set. Możemy to robić pojedynczo:

$('testowy').set('class','nowaKlasa');

Lub ustawiać kilka właściwości naraz podając jako argument tej metody obiekt podobny do obiektu będącego drugim argumentem konstruktora. Zatem zapis:

var nowyDiv = new Element('div',{
    'class':'testowy', 
    'id':'pierwszy', 
    'style' : {
        'background': '#EEE',
        'color': '#777'
    },
    'text': 'przykładowy tekst',
    'events': {
        'click': function(){
            // kod zdarzenia onclick
        },
        'mouseenter': function(){
            // kod zdarzenia onmouseenter
        },
        'mouseleave': function(){
            // kod zdarzenia onmouseleave
        }
    }
});

moglibyśmy zapisać również jako:

var nowyDiv = new Element('div')
 
nowyDiv.set({
    'class':'testowy', 
    'id':'pierwszy', 
    'style' : {
        'background': '#EEE',
        'color': '#777'
    },
    'text': 'przykładowy tekst',
    'events': {
        'click': function(){
            // kod zdarzenia onclick
        },
        'mouseenter': function(){
            // kod zdarzenia onmouseenter
        },
        'mouseleave': function(){
            // kod zdarzenia onmouseleave
        }
    }
});

Warto jeszcze wiedzieć, że w wypadku właściwości html i metody set, możemy jako argumenty podać kilka łańcuchów kodu (x)HTML:

$('testowy').set('html','<em>tekst</em>','<strong>tekst</strong>');

W powyższym wypadku zostaną dodane dwa teksty do elementu - kursywa i pogrubienie.

Gdybyśmy potrzebowali pobrać wartości poszczególnych właściwości wystarczy wykorzystać metodę get:

$('testowy').get('class');

Możemy też pobrać typ elementu:

$('testowy').get('tag');

Powyższy kod zwróci nam na przykład wartość 'div' jeżeli dany element jest divem.

Od razu uprzedzam, że zapis:

$('testowy').set('tag','strong');

Nie zamieni diva w pogrubienie - doda po prostu atrybut tag do tego elementu o wartości strong.

Warto jeszcze wiedzieć, że do czyszczenia danej właściwości służy metoda erase, która ma składnię podobną do metody get - pobiera nazwę właściwości do wyczyszczenia, zatem zapis:

$('testowy').erase('id');

Wyczyści atrybut id naszego elementu i uniemożliwi kolejne odwołania do niego poprzez selektor:

$('testowy')

Własne set, get i erase

MooTools udostępnia nam obiekt, który pozwala nam określić własne implementacje metod set, get oraz erase dla danej właściwości - Element.Properties.

Przykładowo dla właściwości html metoda set wygląda następująco:

Element.Properties.html = {
    set: function(){
return this.innerHTML = Array.flatten(arguments).join('');
    }
};

Jest to o tyle przydatna funkcjonalność, że możemy zmienić obsługę poszczególnych właściwości na wygodniejszą dla nas. Koncepcje wykorzystania pozostawiam Wam - kilka możecie znaleźć w kodzie źródłowym MooTools :)

Zawężamy zakres działań

Metody get, set i erase dają nam dostęp do wszystkich najważniejszych cech elementu - jego zdarzeń, stylu i atrybutów. Gdybyśmy jednak chcieli się ograniczyć tylko do atrybutów elementu to mamy do dyspozycji sześć metod będących odpowiednikami metod get, set i erase. Każda z tych metod ma swój odpowiednik podobnie jak $ i $$ czy getElement i getElements:

  • getProperty,
  • getProperties,
  • setProperty,
  • setProperties,
  • removeProperty,
  • removeProperties

Składnia tych metod nie jest skomplikowana - pobranie pojedynczego atrybutu wymaga zapisu:

$('testowy').getProperty('class');

Natomiast pobranie wartości kilku atrybutów naraz wymaga podania po prostu większej liczby argumentów:

$('testowy').getProperties('class', 'title');

Warto przy tym pamiętać, że getProperty zwraca po prostu wartość atrybutu, a getProperties zwraca obiekt postaci:

{
    'class' : 'nazwaKlasy',
    'title' : 'tytulElementu'
}

Metoda setProperty ma składnię podobną do metody getProperty:

$('testowy').setProperty('class', 'nazwaKlasy');

Natomiast metoda setProperties pobiera jako argument obiekt - na przykład taki jak ten zwracany przez metodę getProperties:

$('testowy').setProperties({
    'class' : 'nazwaKlasy',
    'title' : 'tytulElementu'
});

Jeżeli chodzi o metody removeProperty i removeProperties to składniowo przypominają metody getProperty i getProperties:

$('testowy').removeProperty('class');
$('testowy').removeProperties('class', 'title');

Kilka z tych metod wykorzystamy w przykładzie do tej części kursu.

Gdy potrzeba przechować coś więcej

Najciekawszą nowością w MooTools 1.2 jeżeli chodzi o właściwości elementów są metody store i retrieve. Ileż to razy przydałoby się przechować jakieś informacje o elemencie ? Wcześniej z reguły można było kombinować z tablicami asocjacyjnymi, ukrywaniem danych w dostępnych atrybutach elementu itd. A teraz wystarczy zapisać:

$('testowy').store('jakasCecha', 'jakasWartosc');

I już mamy przechowaną wartość w elemencie - możemy ją odczytać poprzez zapis:

$('testowy').retrieve('jakasCecha');

Dla przykładu stworzymy sobie prosty licznik kliknięć w wybrane elementy strony.

Niech wszystkie elementy dla których mają być zliczane kliknięcia mają jedną cechę wspólną - klasę storage. To na jej podstawie będziemy dokonywali selekcji tych elementów dla celów statystycznych oraz będziemy korzystać z tej cechy w obserwatorze zdarzenia onclick dotyczącym całego dokumentu. Informacje będzie przechowywała cecha o nazwie clickCounter.

Na początek zainicjalizujemy pierwszą wartość - zero dla naszej cechy we wszystkich elementach z klasą storage:

window.addEvent("domready", function(){
    $$('.storage').each(function(el){
        el.store('clickCounter', 0);
    });
});

Do tego musimy dodać stosowny obserwator zdarzenia onclick, który do każdego kliknięcia elementu klasy storage doda operację zwiększenia wartości clickCounter o jeden:

window.addEvent("domready", function(){
    $$('.storage').each(function(el){
        el.store('clickCounter', 0);
    });
 
    document.body.addEvent("click", function(event){
        var elmt = new Event(event).target;
        if(elmt.getProperty('class') == 'storage'){
            var counter = elmt.retrieve('clickCounter');
            counter++;
            elmt.store('clickCounter', counter);
        }
    });
});

Ostatnia ważna sprawa to prezentacja statystyk kliknięć. Ja proponuję by znalazły się one w divie z listą nieuporządkowaną, której pozycje będą prezentowały typ elementu i jego atrybut id oraz ilość kliknięć w postaci :

typ#idElementu - ilość Kliknięć

Dane będą aktualizowane za pomocą funkcji stats:

function stats(){
    var statContent = '';
    $$('.storage').each(function(el){
        statContent += '<li>' + el.get('tag') + '#' + el.get('id') + ' - ' + el.retrieve('clickCounter') + '</li>';
    });
 
    $('stats').set('html', statContent);
}

Oczywiście wywołanie tej funkcji umieszczamy w kodzie obserwatora zdarzenia onclick:

window.addEvent("domready", function(){
    $$('.storage').each(function(el){
        el.store('clickCounter', 0);
    });
 
    document.body.addEvent("click", function(event){
        var elmt = new Event(event).target;
        if(elmt.getProperty('class') == 'storage'){
            var counter = elmt.retrieve('clickCounter');
            counter++;
            elmt.store('clickCounter', counter);
            stats(); // <-- wywołanie funkcji stats
        }
    });
 
    stats(); // pierwsze wywołanie dla zainicjalizowania
});

Cały powyższy przykład w akcji:

PRZYKŁAD

Dla treningu

W ramach utrwalenie sobie poznanych metod klasy Element proponuję stworzyć dwa skrypty:

  • Zmieniający atrybuty href oraz title linka znajdującego się pod trzema obrazkami - zmiana atrybutów ma następować po kliknięciu na dany obrazek - link ma zmieniać swoje cechy tak by dopasować je do obrazka,
  • Skrypt powiązany z prostą wyszukiwarką na stronie (zwykły input typu text oraz przycisk "Szukaj") zawierającej kilka obrazków, który sprawi, że po kliknięciu przycisku "Szukaj" nastąpi przeszukanie atrybutów title wszystkich obrazków i zmianę klasy obrazka na inną w momencie wykrycia danej frazy w atrybucie title obrazka. Opcjonalnie można rozbudować "wyszukiwarkę" tak by wyszukiwała tylko wśród obrazków oznaczonych odpowiednią klasą - na przykład do obrazków o rozmiarach mniejszych niż określone (atrybuty width i height) byłaby dodawana klasa small, a pozostałym klasa big.

Podsumowanie

Wiemy już jak tworzyć nowe elementy dokumentu, jak operować na większości cech elementu, a także jak wykorzystywać elementy do przechowywania danych. W kolejnej części kursu zajmiemy się głównie umieszczaniem elementów w dokumencie ich niszczeniem, a także zajmiemy się elementem iframe.

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

1. metaxy napisał(a):
08 września 2008, 08:59:06

Proponuje zaznaczyć fakt, że dla metody set, czy też obiektu właściwości elementu podczas tworzenia elementu, istnieje istotna różnica między „text”, a „html”.
$(el).set(‘text’, ‘&#39’); // wstawi literalnie tekst tak jak wpisano
$(el).set(‘html’, ‘&#39’); // wstawi znak apostrofu

Jest to szczególnie istotne przy odbieraniu danych z MySQL pobieranych przez Request (często znaki specjalne są dla bezpieczeństwa zamieniane na entities).

2. Piter2k1 napisał(a):
22 września 2009, 01:16:17

W poprzedniej części wspominałeś o ramkach Iframe. Szkoda że jeszcze nie ma nic na ich temat otóż nie potrafię dojść do tego jak dostać się do elementów strony w iframe? Próbowałem tworzyć "new IFrame..." i coś z tym robić ale bezskutecznie... Czy jest jakieś rozwiązanie? Pozdrawiam!

3. Dziudek napisał(a):
22 września 2009, 11:15:58

@Piter2k1 - jeżeli chodzi o IFrame należy zacząć od tego, że ważne jest czy strona w IFrame pochodzi z tej samej domeny czy nie. Jeżeli nie - to nie można zbytnio na takiej zawartości operować (podobne obostrzenia co w wypadku cross-site XMLHttpRequest). Jeżeli jednak dana strona jest w naszej domenie to dostęp do zawartości jest prosty - dostajemy się do samego elementu IFrame, a potem do elementów odwołujemy się tak jakby to był zwykły dokument - przy czym w obrębie obiektu IFrame.

4. Someone napisał(a):
04 kwietnia 2010, 19:29:33

Hej, mam problem IFrame. Mianowicie mam powiększanie zdjęć z miniaturek, jednak całość jest w ramce wbudowanej i chciałbym by klikając na link powiększało się na stronie, a nie w ramce. Dodanie do linka target _parent nie daje żadnych rezultatów.
Jest na to rozwiązanie?

Dodaj komentarz:

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