Pora zająć się właściwie nieodłącznymi elementami każdego skryptu pisanego w JavaScript, a już na pewno pisanego przy użyciu frameworka MooTools - w tej części kursu omówię funkcje i związane z nimi zdarzenia. Zapewnienie jakiejkolwiek interakcji z użytkownikiem jest związane z tymi dwoma zagadnieniami - zdarzenia pozwalają skryptowi reagować na działania użytkownika, a owe reakcje są opisane przez funkcje. MooTools daje nam dostęp do obiektów Function i Event rozszerzonych o wiele przydatnych metod i właściwości.

Obiekt Function

Zacznijmy od obiektu Function - w MooTools posiada on następujące metody: create, pass, attempt, bind, bindWithEvent, delay, periodical, run.

Metoda create jest tutaj podstawą istnienia pozostałych metod, gdyż wszystkie inne metody obiektu Function to po prostu create wywołana z odpowiednimi parametrami - celem ich istnienia jest zwięzłość zapisu, gdyż jak się za chwilę przekonamy, metoda create jest dość rozbudowana.

Przyjmuje ona następujące parametry:

  • bind - uchwyt do obiektu, który będzie w ciele funkcji powiązany z operatorem this. Domyślnie operator this odnosi się do funkcji,
  • event - wartość logiczna określająca czy funkcja będzie używana jako obserwator zdarzeń (z ang. event listener). Domyślna wartość to false. Jeżeli funkca jest obserwatorem zdarzeń to jako pierwszy argument pobiera uchwyt do zdarzenia,
  • arguments - argument/y pobierane przez funkcję. Jeżeli argument jest jeden to zapisujemy go normalnie, w wypadku większej ilości argumentów podajemy je jako tablicę argumentów,
  • delay - opóźnienie wykonania danej funkcji podane w milisekundach,
  • periodical - parametr określający czas, który mija pomiędzy kolejnymi wykonaniami funkcji (jest ona wykonywana okresowo co podaną ilość milisekund),
  • attempt - parametr logiczny, który w wypadku wartości true powoduje wykonanie funkcji, a gdy zostaną stwierdzone błędy w jej działaniu funkcja zwraca wartość logiczną false.

Stwórzmy teraz kopię już istniejącej funkcji zdefiniowanej jako:

var  funkcjaTestowa = function(){
    alert("Test funkcji");
}

Aby skopiować sobie tą funkcję i móc nią dalej manipulować w MooTools zapisujemy co następuje:

var tester = funkcjaTestowa.create();

Od teraz obiekt tester działa tak samo jak nasza funkcjaTestowa. Możemy to łatwo sprawdzić wpisując w konsoli:

tester();

Ujrzymy alert z komunikatem takim jaki generuje właśnie funkcjaTestowa.

Gdybyśmy zapisali :

var tester = funkcjaTestowa.create({delay: 2000});

Wtedy ten sam alert pokazałby się dopiero po dwóch sekundach.

Warto jeszcze zwrócić uwagę na parametry event i arguments - jeżeli oba są podane (event ma wartość true, a arguments jest niepusty lub jest tablicą) wtedy funkcja przy wywołaniu jako pierwszy argument pobiera obiekt zdarzenia, a jako kolejne pobiera argumenty. Jeżeli tylko jeden z parametrów jest określony, wtedy jest on pobierany z pierwszej pozycji.

Metoda create jest przydatna wtedy gdy musimy zmodyfikować kilka parametrów naraz. W sytuacji pojedynczych zmian lepiej stosować pozostałe metody obiektu Function.

Zacznijmy od metody pass - jest to metoda create ograniczona do określenia parametrów arguments i bind. Stwórzmy prostą funkcję dodającą podane jako argumenty liczby:

var dodawanie = function(){
    var suma = 0;
   
    for(var i = 0;i < arguments.length;i++) suma += arguments[i];

    return suma;
}

Zwróćmy uwagę, że powyższa funkcja jest elastyczna - nie ma określonej stałej liczby argumentów - możemy ich podać nieskończenie wiele, a ta funkcja je wszystkie doda.

Stwórzmy jej wersję z różnymi liczbami podanymi jako obiekt dodawanie z metodą pass:

var dwa = dodawanie.pass([1,1]);
var siedem = dodawanie.pass([1,2,4]);
var dwadziescia = dodawanie.pass(20);

Gdy wywołamy powyższe funkcje otrzymamy wyniki:

2
7
20

Dla odmiany teraz będziemy dzielić :) Stworzymy funkcję, która ma błąd składniowy:

var dzielenie = function(){
    return 100/a;
}

Zmienna a nie jest zadeklarowana i normalne wywołanie:

dzielenie();

Spowoduje wystąpienie błędu. Aby tego uniknąć zastosujemy metodę attempt:

dzielenie.attempt();

Zamiast nieoczekiwanego (przyjmijmy, że nieoczekiwany jest :P ) błędu uzyskamy po prostu wartość false.

Warto dodać, że metoda attempt może pobierać dwa argumenty - argumenty funkcji oraz parametr bind.

Kolejna z metod - bind pobiera trzy parametry - bind, arguments i event (w tej właśnie kolejności). Stwórzmy funkcję, która obiektowi do którego odnosi się operator this nada szary kolor tła:

var tlo = function(){
    this.style.backgroundColor = '#EEE';
}

tloNowe = tlo.bind(document.body);

tloNowe();

Przy okazji mała uwaga - w naszym wypadku lepiej byłoby wykorzystać metodę attempt - ponieważ bardzo łatwo podać argument nie będący elementem, któremu można zmienić tło:


var tlo = function(){
    this.style.backgroundColor = '#EEE';
}

tlo.attempt(false,document.body);

Zauważmy jednak, że wywołanie metody attempt jest równoznaczne z wykonaniem naszej funkcji, w wypadku metody bind możemy zmodyfikować funkcję i wywołać ją kiedy chcemy.

Metoda bindWithEvent pobiera takie same parametry jak metoda bind poza event. Jaka jest różnica pomiędzy nimi ? Właśnie to, że nie pobiera parametru event - jest on domyślnie ustawiony jako true. Dzięki temu w ciele funkcji możemy wykorzystywać różne możliwości związane z obiektem Event, ale o tym połączeniu napiszę nieco później gdy zdobędziemy wystarczającą ku temu wiedzę.

Metody delay i periodical to jedne z częściej używanych metod - pozwalają szybko ustalić opóźnienie lub okresowość funkcji. Warto przy ich stosowaniu zapisywać uchwyt do tzw. timera, po to by mieć możliwość zatrzymania odliczania, bądź przerwania okresowego wykonywania funkcji:

var timer = (function(){alert("Test");}).delay(5000);

Możemy przerwać odliczanie wykonaniem kodu:

$clear(timer);

To samo ma miejsce w wypadku metody periodical.

Większość z prezentowanych w tym wpisie funkcji poznamy bliżej podczas manipulowania elementami i tworzenia animacji z użyciem MooTools - wtedy będzie można zobaczyć jak ogromny drzemie w nich potencjał i jak bardzo są one pomocne w skracaniu zapisu.

Ostatnia metoda obiektu Function to metoda run - pobiera ona takie same parametry jak metoda pass, ale jej działanie jest inne - w wypadku użycia metody run następuje od razu wykonanie funkcji. Dla przykłady weźmy nasz kod z przykładu dla metody pass:

var dodawanie = function(){
    var suma = 0;
   
    for(var i = 0;i < arguments.length;i++) suma += arguments[i];

    return suma;
}

var siedem = dodawanie.pass([1,2,4]);

siedem();

i zamieńmy go na wersję z użyciem metody run:


var dodawanie = function(){
    var suma = 0;
   
    for(var i = 0;i < arguments.length;i++) suma += arguments[i];

    return suma;
}

dodawanie.run([1,2,4]);

Krótko mówiąc nie musimy tworzyć nowej zmiennej by uruchomić funkcję.

A gdy jeszcze wykorzystamy chaining obecny we wszystkich obiektach natywnych to zauważymy, że na przykład kod:

var tlo = function(){
    this.style.backgroundColor = '#EEE';
}

tloNowe = tlo.bind(document.body);

tloNowe();

można z powodzeniem zamienić na :

var tlo = function(){
    this.style.backgroundColor = '#EEE';
}

tlo.bind(document.body).run();

To wszystkie metody obiektu Function, omówimy teraz obiekt Event tak by uzupełnić trochę naszą wiedzę, gdyż w większości skryptów JavaScript te dwa obiekty są nierozłączne.

Obiekt Event

Obiekt Event w MooTools posiada kilkanaście właściwości oraz trzy metody. Te metody będą nam przydatne dopiero w wypadku operowania na elementach dokumentu jednak już teraz warto być świadomym ich istnienia.

Metoda stopPropagation jest przydatna na przykład w sytuacji gdy element nadrzędny posiada przypisane jakieś zdarzenie, dla przykładu onclick - wtedy po dodaniu tego zdarzenia do elementu potomnego kliknięcie w tenże element powoduje wywołanie dwóch zdarzeń - elementu potomnego i jego rodzica. Aby tego uniknąć stosujemy metodę stopPropagation. Składnia jest prosta:

obiektKlasyEvent.stopPropagation();

Powyższy kod umieszczony w funkcji przypisanej do obserwatora zdarzeń spowoduje, że żadne zdarzenia z elementów nadrzędnych nie będą wykonywane.

Druga istotna metoda to preventDefault - składnia podobna jak poprzednio:

obiektKlasyEvent.preventDefault();

Metoda ta jest niezwykle przydatna w wypadku zdarzeń onclick takich elementów jak linki czy chociażby przycisk submit w formularzu. Dlaczego ? Domyślnie po kliknięciu w link niezależnie od tego co dalej zrobimy zostaniemy przeniesieni do adresu wskazywanego przez atrybut href linka. Metoda preventDefault blokuje tę standardową akcję. Warto zauważyć, że w wypadku przycisku submit w formularzu jest to nieoceniona pomoc - gdy mamy interfejs który pracuje zarówno z jak i bez JS.

Jeżeli musimy naraz powstrzymać propagowanie zdarzeń i akcję domyślną możemy skorzystać z metody stop:

obiektKlasyEvent.stop();

Powyższy zapis jest równoznaczny zapisowi:

obiektKlasyEvent.stopPropagation();
obiektKlasyEvent.preventDefault();

czyli krótko mówiąc - takie 2w1 :)

Omówię teraz właściwości obiektów klasy Event:

Poniższe właściwości przyjmują wartość true, jeżeli użytkownik kliknął dany klawisz:

  • shift - klawisz Shift,
  • control - klawisz Ctrl,
  • alt - klawisz Alt,
  • meta - metaklawisz.

Obiekt Event ma także właściwość związaną z rolką myszki:

  • wheel - właściwość ta zwraca nam ilość obrotów rolki,

Dzięki obiektowi klasy Event możemy także odczytać informacje o wciskanych klawiszach:

  • code - kod wciśniętego klawisza,
  • key - wartość wciskanego klawisza (małe litery). Dodatkowo klawisze mogą mieć wartości: 'enter', 'up', 'down', 'left', 'right', 'space', 'backspace', 'delete', 'esc'.

Dzięki poniższym właściwościom możemy odczytać dokładną pozycję kursora myszki:

  • page.x - współrzędna x kursora myszki względem całego okna.
  • page.y - współrzędna y kursora myszki względem całego okna.
  • client.x - współrzędna x kursora myszki względem widocznego fragmentu okna.
  • client.y - współrzędna y kursora myszki względem widocznego fragmentu okna.

Na koniec dwie właściwości związane z elementem, którego dotyczy zdarzenie:

  • target - ta właściwość zwraca uchwyt do elementu dla którego zostało wykonane zdarzenie.
  • relatedTarget - dzięki tej właściwości możemy uzyskać uchwyt do elementu nad jakim znalazł się kursor po opuszczeniu obszaru elementu z przypisanym zdarzeniem mouseout.

Ja osobiście bardzo upodobałem sobie właściwość target - dzięki niej mogę drastycznie ograniczyć ilość event listenerów - zamiast tworzyć kilkanaście zdarzeń, tworzę jedno i na podstawie wartości tej właściwości wykonuję odpowiednią operację - jest to nieoceniona pomoc zwłaszcza w wypadku interfejsów opartych na AJAX, gdzie pewne elementy mogą być ładowane dynamicznie - dzięki stosowaniu właściwości target nie trzeba tworzyć kilkunastu event listenerów przy każdym wczytaniu danych :) Z pewnością zaprezentuję tą użyteczną metodę w przykładach omawiających manipulowanie elementami dokumentu - póki co ciągle studiujemy teoretyczne podstawy MooTools ;)

Pozostaje nam jeszcze obiekt Event.keys - zawiera on kody wybranych klawiszy. Jeżeli chcemy do wartości zwracanych przez właściwość key obiektu Event dodać własne klawisze z własnymi nazwami stosujemy zapis:

Event.keys.nazwaKlawisza = kodKlawisza;

Dzięki temu możemy potem stosować zapis postaci:

if(event.key == "nazwaKlawisza") { ... }

Teorię już znamy - na praktykę przyjdzie czas podczas omawiania pliku Element.Event i nie tylko ;)

W następnej części kursu zajmiemy się obiektami String i Number.

Komentarze do wpisu "MooTools 1.2 - obiekty natywne - funkcje i zdarzenia":

1. bobiko napisał(a):
12 lutego 2008, 02:20:46

No mistrzu, to akurat się przyda na pewno :) zwłaszcza gdy :) sam się bawię z Mootools’em :)

Dziękować:)

2. Dominik Porada napisał(a):
12 lutego 2008, 04:29:58

IMO świetny wpis. Tak trzymać!

3. Bigismall napisał(a):
12 lutego 2008, 21:48:10

Dobrze, że znowu zacząłeś pisać :)

4. Dziudek napisał(a):
12 lutego 2008, 23:05:00

Dziękuję za te wszystkie pozytywne i miłe komentarze – motywacja do pisania kolejnych wpisów jeszcze bardziej ++ :)

5. Siergiej napisał(a):
23 lutego 2008, 22:19:30

Przepraszam za delikatny OT, ale może ktoś słyszał o odpowiedniku funkcji periodical dla jQuery?

6. Dziudek napisał(a):
23 lutego 2008, 22:39:11

Siergiej – ostatnio zgłębiam dość intensywnie jQuery i nie spotkałem takiej funkcjonalności w tej bibliotece. Generalnie pod względem rozszerzania możliwości obiektów natywnych JS jQuery w stosunku do MooTools leży i kwiczy ;) Musisz chyba stosować tradycyjne setInterval .

Dodaj komentarz:

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