Jedni nie korzystają z nich wcale, niektórzy tylko po to aby zwiększyć funkcjonalność tworzonych przez siebie stron, a u jeszcze innych zauważalny jest przepych tego typu rozwiązań. Biblioteki programistyczne języka JavaScript, bo o ich wykorzystaniu tu mowa to źródło bardzo różnorodnych, nie tylko funkcjonalnych, ale także estetycznych efektów. Sieć aż kipi od dobrych i słabych, lepiej oraz słabiej wytłumaczonych przykładów użycia możliwości MooTools, jQuery, Prototype z Scriptaculous, czy innych mniej powszechnych frameworków.
Jednym z takich efektów jest możliwość stworzenia animowanego, graficznego podświetlenia pojawiającego się np. nad grafiką wywołującą animację. Interaktywność taka została opisana na NetTuts z wykorzystaniem MooTools. My osiągniemy taki wynik dzięki zastosowaniu jQuery (w jednym przykładzie) oraz dodatkowo także za pomocą Prototype wraz z Scriptaculous (w drugim przykładzie).
Oczekiwany efekt.
Krok 1: Za co się chwycić na początku…
Na początek musisz wiedzieć w jakim celu potrzebny jest Ci prezentowany w tym artykule efekt. Menu? Wyświetlanie dodatkowych informacji w graficznej liście produktów? Czy może szybki, animowany splash? Wybór jest Twój i podług niego będziesz musiał zaopatrzyć się w dodatkowe, niezbędne elementy do wykonania podświetlenia.
Chodzi tu mianowicie o grafiki, których musi być dwa razy więcej niż elementów podatnych na działanie mechanizmu. Powiedzmy, jeżeli chcemy w pięcioelementowym menu zastosować w każdym zdarzenie po najechaniu myszką zgodne z przesłaniem tego artykułu to potrzebujemy dziesięciu grafik. Pięć opisujących przyciski menu i drugie tyle będące „treścią” pojawiającą się po podświetleniu.
Po uporaniu się z wizualną częścią problemu oraz strony internetowej możemy ruszyć krok dalej.
Krok 2: Zaopatrujemy się w jQuery i/lub Prototype i Scriptaculous!
jQuery to aktualnie najpopularniejsza biblioteka. I najłatwiej ją skatalogować w czeluścia własnego projektu. Wystarczy ze strony głównej pobrać wersję 1.3.1 production/Minified i umieścić ją w obrębie plików tworzonego przez nas przykładu (niezbędny będzie tylko plik jquery-1.3.1.min.js).
Z Prototype sprawa jest ciut bardziej skomplikowana, bo prócz standardowego frameworka musimy pobrać także dodatkowy interfejs w postaci Scriptaculous, dzięki któremu uzyskamy dostęp do efektu pozwalającego na dynamiczne zmienianie właściwości CSS elementów strony. Ściągamy więc wersję 1.6.0.3 pierwszej biblioteki, oraz paczkę z wersją 1.8.2 drugiej. Z obydwu wyodrębniamy pliki i w ramach folderu tworzonego przez nas projektu umieszczamy tylko prototype.js oraz effects.js (z drugiego archiwum).
W przypadku tego artykułu umownie pliki związane z frameworkami będą znajdować się w podkatalogu javascript folderu głównego. Obydwa przykłady (dotyczące, jeden jQuery, a drugi Prototype z Scriptaculous) będą oczywiście wykonywane w osobnych plikach znajdujących się w dwóch różnych katalogach.
Przykładowe rozdzielenie implementacji przykładów na dwa katalogi. W naszym przypadku pliki .js znajdują się dodatkowo w podkatalogu javascript.
Krok 3: Tworzymy strukturę XHTML
Atutem naszego rozwiązania jest kompatybilność z serwowaniem dokumentu XHTML w postaci application/xhtml+xml, czego bardzo często brakuje w przypadku efektów opartych na bibliotekach JS. Z racji tego także, że i w przypadku Prototype i jQuery struktura strony pozostaje niezmienna to obojętnie który framework wykorzystujesz poniższe tłumaczenie i partie kodu będą prawidłowe.
Z powodu tego w jaki sposób będziemy wysyłać treść strony posłużymy się małą częścią kodu PHP, a co za tym idzie plik korzystający z naszego mechanizmu musi mieć też takie rozszerzenie (no chyba, że serwer jest inaczej skonfigurowany, ale to już problematyka do rozwiązania na inny temat).
<?php
if ( stristr($_SERVER['HTTP_ACCEPT'], 'application/xhtml+xml') ) // jeżeli przeglądarka obsługuje application/xhtml+xml
{
header("Content-Type: application/xhtml+xml; charset=utf-8"); // wysłanie odpowiednich nagłówków
print '<?xml version="1.0" encoding="utf-8"?>'."\r\n";
print '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"'."\r\n";
print '"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'."\r\n";
}
else // wysłanie dokumentu jako text/html dla przeglądarek nie obsługujących typu zawartości pliku z powyższego warunku, np. dla IE
{
header("Content-Type: text/html; charset=utf-8");
print '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'."\r\n";
print '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'."\r\n";
}
?>
Poniżej dodajemy uniwersalny układ strony. Ważnym ułatwieniem jest możliwość tworzenia odnośników z elementów graficznych podatnych mechanizmowi, a także fakt, że nie korzystamy w nim z tagów img, a efektu zbliżonego do sliding-doors w celu wyświetlania obrazów.
Krok 4: Stylizujemy strukturę strony za pomocą CSS
Posługując się metodami pozycjonowania elementów dostępnymi w kaskadowym arkuszu stylów możemy operując na elementach o identyfikatorach siteContainer, pageContainer, highlightsContainer oraz divach potomnych ułożyć i wystylizować wygląd, w tym położenie jak na wyżej zamieszczonym filmiku (screenie) obrazującym wykonanie zadania z tego artykułu.
Do wszystkich bloków kodu CSS odwołujących się do tagów zawierających identyfikatory grafik zostały dodane także właściwości background z adresem pliku tła.
W naszym przypadku poniższy kod zapisujemy do pliku stylesheet.css.
/* ustawienia domyślne dla ciała strony (w poprawnie wysyłanym XHTML jest to html+body, a nie tylko body) */
html, body {
margin: 0px;
padding: 0px;
background: #000 url('bg.png') repeat-x;
}
#siteContainer {
margin: 150px auto 0px auto; /* marginesy - wyśrodkowanie poziome */
width: 573px;
height: 345px;
position: relative; /* relatywna pozycja, kontener */
background: transparent url('container.png') no-repeat top left;
}
#pageContainer {
position: absolute; /* pozycja względem #siteContainer */
z-index: 5; /* ponad ciałem strony i pod #highlightsContainer */
top: 128px;
left: 0px;
}
#highlightsContainer {
position: absolute; /* pozycja względem #siteContainer */
z-index: 10; /* ponad pozostałymi elementami */
left: 178px;
top: 30px;
}
/* ustawienie w linii wraz z zmianą wyglądu kursora */
#pageContainer > div {
float: left;
cursor: pointer;
}
/* rozmiary klikalnych divów potomnych znajdujących się w kontenerze listy grafik podatnych na działanie mechanizmu */
#pageContainer > div a {
width: 178px;
height: 178px;
display: block;
}
#page1 {
margin-right: 19px; /* prawy margines - odstęp od kolejnego diva */
}
#page1 a {
background: url('icon_1.png') no-repeat; /* tło grafiki podatnej na działanie efektu */
}
#page2 {
margin-right: 20px; /* prawy margines - odstęp od kolejnego diva */
}
#page2 a {
background: url('icon_2.png') no-repeat; /* tło grafiki podatnej na działanie efektu */
}
#page3 a {
background: url('icon_3.png') no-repeat; /* tło grafiki podatnej na działanie efektu */
}
/* rozmiary wszystkich potomków typu div kontenera zawierającego podświetlenia */
#highlightsContainer > div {
position: absolute;
width: 222px;
height: 101px;
display: block;
}
/* pliki tła w pojawiających się podświetleniach */
#highlight1 {
background: transparent url('highlights_1.png') no-repeat;
}
#highlight2 {
background: transparent url('highlights_2.png') no-repeat;
}
#highlight3 {
background: transparent url('highlights_3.png') no-repeat;
}
Krok 5a: Dodajemy jQuery do dokumentu
Tego, czego zabrakło dotychczasowo w naszym dokumencie to załączenie bibliotek oraz pliku .js w którym będzie znajdować się kod animujący pożądany przez nas efekt.
Dla jQuery w sekcji head należy dodać pliki jquery-1.3.1.min.js oraz product-highlighter.js (który umownie będzie zawierał dodatkowy kod).
Krok 5b: Dodajemy Prototype z Scriptaculous do dokumentu
Tym razem musimy dodać jeden plik więcej. Bibliotekę (prototype.js), jej dodatkowy interfejs, a dokładniej plik zawierający obiekt Effect (effects.js) oraz jak w powyższym przypadku plik z naszym kodem animacji (product-highlighter.js).
Krok 6a: Implementujemy kod animacji z użyciem jQuery
Jak to bywa w przypadku tego frameworka, aby jakieś zdarzenie działało poprawnie powinno się je umieszczać w funkcji $(document).ready(), której zawartość zostanie załadowana w momencie załadowania drzewa dokumentu.
$(document).ready(function() {
[kod]
});
W [kod] musimy przypisać (do tablicy) wg. klasy wszystkie grafiki wyświetlane podczas podświetlenia, ustawić parametry podstawowe CSS oraz stworzyć sprawdzanie w pętli, czy dana grafika o klasie .pages nie jest najechana przez kursor i w zależności o danego trybu (kursor na/kursor poza) wykonać pożądaną animacji (wyłonienie dodatkowego tła / zanikanie dodatkowego tła).
Poniższy kod umieszczamy w pliku product-highlighter.js.
$(document).ready(function() {
// tablica elementów o klasie .highlights
var highlights = $('.highlights');
// ustawienie pełnej przezroczystości elementów pojawiających się w czasie najechania myszką na obiekty podatne efektowi oraz widzialności ich kontenera
$('.highlights').css('opacity', 0);
$('#highlightsContainer').css('visibility', 'visible');
// sprawdzanie każdego elementu podatnego mechanizmowi
$('.pages').each(function(i) {
// jeżeli na danym elemencie znajduje się kursor
$(this).mouseover(function() {
// wykonanie animacji grafiki wyłanianej i przypisanej do najechanego elementu (margines o 15px w górę i brak przezroczystości w czasie 0,5 sekundy)
$(highlights[i]).animate({
opacity: 1,
marginTop: '-15px'
}, 500);
}).mouseout(function(){ // jeżeli na danym elemencie nie znajduje się już kursor
$(highlights[i]).animate({
opacity: 0,
marginTop: '-0px'
}, 500);
});
});
});
Należy jeszcze wyjaśnić dokładniej w jaki sposób działa $(highlights[i]).animate(). Mianowicie przy każdej iteracji pętli $('.pages').each() przekazuje ona do parametru function(i) aktualny numer elementu na którym się znajduje. Ponieważ w id pageContainer znaczniki potomne muszą być posegregowane i musi być ich tyle samo co obiektów graficznych w highlightsContainer to jeżeli kursor znajduje się na pierwszym podatnym na efekt obrazie to w podświetleniu wyłania się także pierwsza grafika. Wszystko to dzięki wyłuskaniu jej z tablicy highlights poprzez parametr i.
Krok 6b: Implementujemy kod animacji z użyciem Prototype z Scriptaculous
Event.observe – uchwyt rejestrujący zdarzenie na drzewie dokumentu. Funkcja obiektu składającego się na bibliotekę Prototype. Posiada cztery argumenty:
element – obserwowany element DOM, mogący być referencją do niego bądź jego identyfikatorem,
nazwaZdarzenia – standaryzowana wg. DOM Level 2 Events nazwa zdarzenia, np. load,
Podobnie w Prototype obserwujemy zdarzenie, ale tym razem załadowania całej strony w celu późniejszej obserwacji aktywności kursora na wybranych elementach aktywnych. Można oczywiście podobnie jak w poprzednim podpunkcie wykonać obserwacje zdarzeń wraz z załadowanie DOM (drzewa dokumentu) poprzez użycie document.observe('dom:loaded', function() {}). To tylko kwestia osobistego wyboru.
Dalsze postępowanie jest adekwatne do tego opisanego w przypadku zastosowania jQuery. Z tymże, tablicę elementów o danej klasie pobiera się poprzez podwójny znak dolara ($$), a najechanie oraz zjechanie kursorem poza zadany obszar rozpoznaje się także poprzez obiekt Event i metodę observe(). Do animacji służy funkcja Morph instancji Effect z pliku effects.js interfejsu Scriptaculous.
Event.observe(window, 'load', function() {
var highlights = $$('.highlights'); // utworzenie tablicy
$$('.highlights').invoke('setStyle', { opacity: 0 }); // ustawienie stylu przezroczystości
$$('#highlightsContainer').invoke('setStyle', { visibility: 'visible' }); // widzialność kontenera
$$('.pages').each(function(v, i) { // pętla
Event.observe(v, 'mouseover', function() { // zdarzenie wykonywane w momencie pojawienia się kursora na elemencie
new Effect.Morph(highlights[i], { // animacja
style: 'opacity: 1; margin-top: -15px;',
duration: 0.5 // czas 0,5 sekundy
});
});
Event.observe(v, 'mouseout', function() { // zdarzenie wykonywane w momencie wyjechania kursorem poza element
new Effect.Morph(highlights[i], {
style: 'opacity: 0; margin-top: 0px;',
duration: 0.5
});
});
});
});
Tym razem do funkcji w $$('.pages').each() przekazywane są dwa parametry: v i i. Pierwszy z nich jest odpowiednikiem this i wskazuje na aktualnie przetwarzany element tablicy znaczników o klasie .pages. Drugi to numer pokazujący który z kolei tag jest aktualnie sprawdzany. Inaczej pisząc jego zadanie jest równoznaczne do działania parametru i w przykładzie z jQuery.
Effect.Morph – metoda interfejsu Scriptaculous >= 1.7. Pozwala na animacyjną zmianę właściwości CSS elementu. Przyjmuje jeden podstawowy argument style zawierający w sobie właściwości i wartości CSS w formie oryginalnej bądź w postaci Camel-Case, czyli bez spacji i znaków specjalnych pomiędzy kilkoma członami nazwy właściwości. Opcjonalnie można dodawać kolejne parametry rdzenia obiektu Effect, takie jak duration (czas animacji), czy transition (rodzaj animacji, wymaga Effect.Transitions).
Stworzyłem dwa gotowe przykłady, których analiza pozwoli Wam jeszcze bardziej zrozumieć jak stworzyć ten efekt. Pierwszy, za pomocą jQuery. Drugi, za pomocą Prototype z Scriptaculous.
Jeżeli chcecie dowiedzieć się więcej o tych bibliotekach to zapraszam do ich dokumentacji (Prototype, jQuery).
Wystarczy dodać zdarzenie stop() przed animacją dla pojawienia się kursora nad obiektem i po jego zejściu. Czyli zamiast:
jQuery(highlights[i]).animate({
->
jQuery(highlights[i]).stop().animate({
I zamiast:
jQuery(highlights[i]).animate({
->
jQuery(highlights[i]).stop().animate({
Co do Prototype to powinien w standardzie działać lepiej pod tym względem niż jQ, nie mniej jednak można dodać także zdarzenia stop() przed wywołaniem Morph, a także dodać do parametr do function w observe w celu zatrzymania aktualnych animacji. Czyli zamieniamy:
Taka mała uwaga: jak szybko sobie przejadę w te i we w te po divach „pages” będzie się animować do bólu, aż skończy się wszystko co jest w kolejce :)
Wystarczy dodać zdarzenie
stop()przed animacją dla pojawienia się kursora nad obiektem i po jego zejściu. Czyli zamiast:jQuery(highlights[i]).animate({->
jQuery(highlights[i]).stop().animate({I zamiast:
jQuery(highlights[i]).animate({->
jQuery(highlights[i]).stop().animate({Co do Prototype to powinien w standardzie działać lepiej pod tym względem niż jQ, nie mniej jednak można dodać także zdarzenia
stop()przed wywołaniemMorph, a także dodać do parametr dofunctionwobservew celu zatrzymania aktualnych animacji. Czyli zamieniamy:Event.observe(v, 'mouseover', function() {Na:
Event.observe(v, 'mouseover', function(event) { Event.stop(event);To samo robimy w
observe->mouseout.Powinno działać.
Gdzie na stronie mozna znaleźć maila do Ciebie ?
m1chu #at# m1chu #dot# eu (#at# = @, #dot# = . – bez spacji) ;]
W gruncie rzeczy… tak jak patrzę, to niemożna znaleźć. Muszę to gdzieś umieścić… tylko jeszcze nie wiem gdzie ;]