Opisywałem już jak tworzyć efekty wykorzystujące zmianę jednej właściwości CSS (Fx.Style), kilku właściwości (Fx.Styles), a dziś dowiemy się jak wykonywać te operacje na wielu elementach naraz - do tego właśnie służy plik fx.elements.js

Głównym składnikiem tego pliku jest oczywiście klasa Fx.Elements, która posiada tylko jedną metodę - start. Oczywiście poza tym klasa ta dziedziczy wszystkie opcje klasy Fx.Base.

Składnia metody start tej klasy jest trochę bardziej skomplikowana niż wypadku poprzednich metod, bo jako argument przyjmuje dość rozbudowany obiekt.

Bardzo ważną cechą tej klasy jest fakt, że możemy za jej pomocą animować każdy z grupy elementów na inny sposób.

Składnia za pomocą której tworzymy sam efekt jest bardzo prosta:

var efekty = new Fx.Elements($$('elementy'),{opcje});

Gdzie zmienna $$('elementy') oznacza dowolny zbiór elementów, a obiekt {opcje} to pozostałe parametry efektu dziedziczone z klasy Fx.Base .

Bardziej złożona jest budowa metody start:

efekty.start({
   "0":{
      "wlasciwosc1" : [start,koniec],
      "wlasciwosc2" : [start,koniec]
   },
   "1":{
      "wlasciwosc" : [start,koniec]
   },

   ...
   "5":{
      "wlasciwosc" : koniec
   }
});

Metoda start pobiera obiekt w którym kolejne pola są identyfikatorami elementów w tablicy zwracanej przez funkcję selekcjonującą elementy - numerowanie zaczyna się od zera. Obiekt przypisany do takiego identyfikatora składa się z właściwości i zakresu wartości (lub wartości końcowej) w jakim przebiega animacja tegoż elementu.

Według mnie ręczne zapisywanie tego typu obiektów jest mało sensowne chyba, że mamy do czynienia z bardzo zróżnicowanymi animacjami dla elementów z danej grupy. W innych wypadkach polecam tworzenie obiektów z identyfikatorami w pętli i dołączanie ich do tablicy w sposób dynamiczny - dzięki temu zyskamy na elastyce rozwiązania (dodanie kolejnych elementów do kodu struktury animacji nie wymaga dodatkowych ingerencji w kod JavaScript).

Zaletą klasy Fx.Elements jest fakt, że nie tworzymy kilkunastu obiektów efektów tylko jeden obiekt w momencie gdy chcemy na różne sposoby animować różne elementy naraz.

Zapewne kojarzycie menu ze strony głównej mootools - jest tam zastosowany ładny efekt, który można także znaleźć na stronie z demami . Na tym demie będę się wzorował w swoim przykładzie, jednak od siebie dodam iż mój kod zajmuje 19 linijek w stosunku do 27 jakie zajmuje wersja oryginalna. Moja wersja jest także trochę wydajniejsza bo wykonuje mniej zbędnych operacji. Także ten przykład będzie dziś mówił nie tylko o Fx.Elements, ale także o optymalizacji kodu (troszeczkę ;) ).

Zapoznajmy się może z wersją oryginalną:

var szNormal = 117, szSmall = 100, szFull = 219;
var kwicks = $$("#kwicks .kwick");
var fx = new Fx.Elements(kwicks, {wait: false, duration: 300, transition: Fx.Transitions.Back.easeOut});

kwicks.each(function(kwick, i) {
   kwick.addEvent("mouseenter", function(event) {
      var o = {};
      o[i] = {width: [kwick.getStyle("width").toInt(), szFull]}
      kwicks.each(function(other, j) {
          if(i != j) {
            var w = other.getStyle("width").toInt();
            if(w != szSmall) o[j] = {width: [w, szSmall]};
         }
      });
      fx.start(o);
   });
});

$("kwicks").addEvent("mouseleave", function(event) {
   var o = {};
   kwicks.each(function(kwick, i) {
      o[i] = {width: [kwick.getStyle("width").toInt(), szNormal]}
   });
   fx.start(o);
});

Wygląda dość skomplikowanie, ale wraz z moją wersją wyjaśnię co i jak.

Zacząłem oczywiście od zmiennych wykorzystywanych w dalszym kodzie:

var opcje = $$("#menu li");
var obiekt = {}, obiekt_l = {};
var efekt = new Fx.Elements(opcje, {wait: false, transition: Fx.Transitions.Back.easeOut});

Jak widać stworzyłem zmienną opcje, która jest kolekcją wszystkich opcji listy. Do tego stworzyłem dwa obiekty, które zostaną wykorzystane w metodach start efektu. No i oczywiście zmienna definiująca sam efekt. W stosunku do oryginału usunąłem zmienne odpowiedzialne za rozmiary elementów - u mnie te liczby są wykorzystywane tylko raz więc tworzenie zmiennych było bezsensowne. kwicks to moje opcje, #menu to #kwicks, a klasę .kwick zastąpiłem po prostu elementem li - nie widziałem potrzeby generowania dodatkowych klas w kodzie skoro mogę się odwołać po typie elementów. Oczywiście doszły moje dwa obiekty, które w oryginale znajdują się w ciele funkcji.

Sprawę zdarzeń mouseenter zrealizowałem w następujący sposób:

opcje.each(function(opcja, i){
   opcja.addEvent("mouseenter", function(){
      opcje.each(function(x,j){
         (i != j) ? obiekt[j] = {width: 100} : obiekt[j] = {width: 219};
      });
      efekt.start(obiekt);
   });
   obiekt_l[i] = {width: 117};
});

Jak widać przy każdej z opcji dodawane jest zdarzenie i generowany jest obiekt dla metody start. W stosunku do oryginału zrezygnowałem z określonego przedziału w jakim odbywa się animacja oraz skróciłem generowanie obiektu do trzech linijek dzięki skróconej postaci instrukcji warunkowej if.

Dodatkowo przy okazji głównej pętli realizuję w tym kodzie generowanie obiektu dla metody start użytej pryz zdarzeniu mouseleave - dzięki temu pozbyłem się tam dodatkowej pętli generującej obiekt.

Generowanie zdarzenia mouselave skróciło mi się do trzech linijek:

$("menu").addEvent("mouseleave", function(){
   efekt.start(obiekt_l);
});

Obiekt obiekt_l mam wygenerowany wcześniej więc wystarczyło dodać wywołanie metody start klasy Fx.Elements. I tym sposobem skróciłem 27-linijkowy kod do 19-linijkowego kodu, który jest według mnie wydajniejszy bo pozbyłem się z niego zbędnych zmiennych i pętli:

window.addEvent("domready",function(){
   var opcje = $$("#menu li");
   var obiekt = {}, obiekt_l = {};
   var efekt = new Fx.Elements(opcje, {wait: false, transition: Fx.Transitions.Back.easeOut});

   opcje.each(function(opcja, i){
      opcja.addEvent("mouseenter", function(){
         opcje.each(function(x,j){
            (i != j) ? obiekt[j] = {width: 100} : obiekt[j] = {width: 219};
         });
         efekt.start(obiekt);
      });
      obiekt_l[i] = {width: 117};
   });

   $("menu").addEvent("mouseleave", function(){
      efekt.start(obiekt_l);
   });
});

I oczywiście przykład prezentujący moją wersję menu:

PRZYKŁAD

Jak widać przy dość krótkim kodzie (można go jeszcze bardziej skrócić usuwając zbędne białe znaki, ale chciałem zadbać o jako taką czytelność) możemy uzyskać miły dla oka efekt :) Poza tym (to informacja dla tych co mają gdzieś przyjemności dla oka :) ) tego typu efekt pozwala zmniejszyć ilość miejsca potrzebnego do prezentacji informacji - część mniej kluczowych informacji widoczna jest po najechaniu na daną opcję menu (oczywiście mówimy tu o rzeczywistym wykorzystaniu, a nie przykładzie).

W następnej części kursu omówię plik Fx.Scroll.js .

Komentarze do wpisu "Mootools 1.1 - Fx.Elements.js":

1. Slavo napisał(a):
04 sierpnia 2007, 00:25:50

Dziudas, przynudzasz :P

2. Dziudek napisał(a):
04 sierpnia 2007, 00:26:59

@Slavo – jeszcze 14 części i będzie po bólu (dla niektórych jak widzę) ;D

3. Slavo napisał(a):
04 sierpnia 2007, 21:57:36

Nie no, może akurat mnie skusisz na to MooTools ;)
Kto wie..

4. Dziudek napisał(a):
04 sierpnia 2007, 22:00:54

@Slavo – jak masz wolny czas to polecam się zainteresować tym tematem ;] Zawsze można później coś ciekawego stworzyć dla realizowanego projektu, zamiast tracić czas na szukanie gotowców ;)

Dodaj komentarz:

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