MooTools 1.2 - klasa Chain

03 sierpnia, 2008

Miło mi zakomunikować, że jest to ostatni wpis związany bardziej z zagadnieniami teoretycznymi niż praktycznymi, ale za to dość ważny - jeżeli będziecie chcieli tworzyć zaawansowane animacje złożone z kilku efektów następujących po sobie to klasa Chain bez wątpienia bardzo Wam pomoże. Zresztą przyda się ona w każdym wypadku, gdzie wymagane jest wykonywanie operacji w określonej kolejności.

Zaczynamy podobnie

Tak jak w wypadku klas Events i Options, aby skorzystać z możliwości klasy Chain musimy ją dodać we właściwości Implements:

var Testowa = new Class({
    Implements: Chain,
 
    // dalszy kod klasy
});

Oczywiście można to zrobić też poprzez metodę implement obiektu Class:

Testowa.implement(Chain);

A w odróżnieniu do dwóch poprzednich klas, możemy też używać tej klasy poprzez utworzenie obiektu tej klasy:

var Lancuch = new Chain();

Użycie klasy Chain w konstruktorze

Odwołując się do metody chain, możemy utworzyć łańcuch z funkcji podanych jako argumenty konstruktora:

var Testowa = new Class({
    Implements: Chain,
 
    initialize: function(){
        this.chain.apply(this, arguments);
        this.callChain();
        this.callChain();
        this.callChain();
    }
});

Pamiętamy, że samo this.chain.apply(this, arguments) utworzy jedynie łańcuch, natomiast jego wywołanie następuje dopiero po użyciu metody callChain w odpowiedniej ilości - o metodzie callChain napiszę w dalszej części wpisu - na razie wystarczy nam wiedza, że potrzeba ją wywołać tyle razy ile "ogniw" posiada łańcuch, by w efekcie wywołać wszystkie ogniwa łańcucha po kolei.

Późniejsze wywołania typu:

var test = new Testowa(
    function(){
        alert('Pierwsze ogniwo');
    },
    function(){
        alert('Drugie ogniwo');
    },
    function(){
        alert('Trzecie ogniwo');
    }
);

Spowodują pokazanie się trzech alertów w odpowiedniej kolejności. Warto jeszcze dodać, że zapis:

this.callChain();
this.callChain();
this.callChain();

Możemy zamienić na bardziej uniwersalny i krótszy zapis:

while(this.$chain.length) this.callChain();

Powyższy kod wykona tyle ogniw łańcucha ile podamy - nie jesteśmy zatem w tym wypadku niczym ograniczeni.

$chain.length odnosi się do długości łańcucha this.$chain - to bardzo ważne by odróżniać this.chain i this.$chain w naszej klasie - pierwsze to metoda, która pozwala dodawać nowe elementy łańcucha, a drugie to tenże łańcuch. Dlaczego pętla while w tym wypadku sprawuje się tak dobrze ? Wyjaśnię to przy okazji omawiania metody callChain.

Dodajemy nowe ogniwa łańcucha

Metoda chain pozwala nam na dołączanie nowych ogniw do naszego łańcucha przechowywanego we właściwości $chain.

Zatem gdybyśmy chcieli by nasz łańcuch alertów miał zawsze charakterystyczne ostatnie ogniwo, musielibyśmy zapisać:

var Testowa = new Class({
    Implements: Chain,
 
    initialize: function(){
        this.chain.apply(this, arguments);
        this.chain(function(){alert('Ostatnie ogniwo');});
        while(this.$chain.length) this.callChain();
    }
});

Gdy użyjemy poprzednio użytego kodu:

var test = new Testowa(
    function(){
        alert('Pierwsze ogniwo');
    },
    function(){
        alert('Drugie ogniwo');
    },
    function(){
        alert('Trzecie ogniwo');
    }
);

Otrzymamy cztery alerty - pierwsze, drugie, trzecie i ostatnie ogniwo. Oczywiście metoda chain może pobierać kilka funkcji naraz - zamiast pisać powyższy dość długi kod, możemy umieścić go w środku naszej metody (oczywiście tracimy wtedy dowolność treści trzech pierwszych alertów:

var Testowa = new Class({
    Implements: Chain,
 
    initialize: function(){
        this.chain(
            function(){
                alert('Pierwsze ogniwo');
            },
            function(){
                alert('Drugie ogniwo');
            },
            function(){
                alert('Trzecie ogniwo');
            }
        );
        this.chain(function(){alert('Ostatnie ogniwo');});
        while(this.$chain.length) this.callChain();
    }
});

I wtedy pokazanie łańcucha wymaga mniej kodu:

var test = new Testowa();

Warto pamiętać, że klasy oparte na Fx i Request mają zaimplementowaną obsługę klasy Chain - ale więcej o tym powiązaniu dowiecie się podczas opisu tych klas.

Czyścimy łańcuch

Jeżeli będziemy mieli potrzebę wyczyszczenia naszego łańcucha wystarczy zastosować metodę clearChain:

this.clearChain();

Metoda ta nie pobiera żadnych argumentów. Można jej używać w różnych sytuacjach - gdy chcemy w pewnym momencie zacząć tworzyć łańcuch operacji od nowa i nie mamy pewności, że jest on pusty. Może też zajść potrzeba wyczyszczenia łańcucha operacji w trakcie wykonywania jednego z ogniw, jeżeli zajdą odpowiednie warunki itp. itd. Do takich sytuacji najlepiej właśnie użyć tej prostej w użyciu metody klasy Chain.

Prawie jak stos

Przyszła pora na metodę callChain - aby zrozumieć istotę jej działania najlepiej wyobrazić sobie nasz łańcuch jako stos ogniw ułożonych w ustalonej kolejności. Metoda callChain powoduje wykonanie pierwszego ogniwa - tego znajdującego się na samym spodzie, a następnie usuwa je. Po tej operacji drugie ogniwo (o ile istnieje) staje się pierwszym ogniwem - tak możemy wywoływać metodę callChain aż do wykonania wszystkich ogniw. Jeżeli kolejne ogniwo nie istnieje (wykonywane aktualnie ogniwo jest jedynym w łańcuchu) to metoda callChain zwraca wartość false.

Dzięki takiej metodzie działania callChain nasz zapis:

while(this.$chain.length) this.callChain();

Działał poprawnie - po każdym wykonaniu this.callChain() wartość this.$chain.length malała o 1, aż do momentu w którym osiągnęła wartość 0, która jak wiadomo jest uznawana za odpowiednik wartości logicznej false - i to spowodowało zakończenie pętli while w odpowiednim momencie.

Warta uwagi jest jeszcze jedna bardzo ciekawa cecha metody callChain. Otóż może ona przyjmować argumenty wywołania następnej funkcji w łańcuchu - zatem wywołując pierwsze ogniwo łańcucha, możemy określić z jakimi argumentami wywoła się drugie ogniwo. Najlepiej pokaże to przykład, który wyświetli potęgi liczb od 6 do 1:

var Testowa = new Class({
    Implements: Chain,
 
    initialize: function(){
        this.chain(
            function(){
                alert(6*6);
            },
            function(i){
                alert(i*i);
            },
            function(i){
                alert(i*i);
            },
            function(i){
                alert(i*i);
            },
            function(i){
                alert(i*i);
            },
            function(i){
                alert(i*i);
            },
        );
 
        while(this.$chain.length) this.callChain(this.$chain.length);
    }
});
 
var test = new Testowa();

Wraz ze zmniejszającą się wartością długości łańcucha operacji, otrzymujemy coraz mniejsze wartości potęg liczb, które są przekazywane jako argument metody callChain.

Podsumowanie

I tak oto zakończyliśmy część kursu poświęconą programowaniu obiektowemu w MooTools 1.2 oraz większy blok - części teoretycznej kursu. W następnych częściach zajmiemy się klasą Element, która pozwoli nam na manipulacje wyglądem strony i pozwoli tworzyć interaktywne przykłady - oczywiście wiedza zdobyta do tej pory będzie nam często przydatna :)

Komentarze do wpisu "MooTools 1.2 - klasa Chain":

1. ewel napisał(a):
05 sierpnia 2008, 18:05:29

a może udałoby Ci sie jakos opisac roznice miedzy MooTools 1.1 a 1.2? mysle ze osoby ktore uzywaly 1, w tym ja chetnie by poczytaly ;)

2. Dziudek napisał(a):
05 sierpnia 2008, 18:36:19

@ewel – niczego nie obiecuję, ale może jak starczy mi zdrowia to pomiędzy Core i More opublikowałbym kilka wpisów o tych różnicach – czyli Rdzeń frameworka, Obiekty natywne itd. – różnice w poszczególnych sekcjach ;)

Dodaj komentarz:

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