Wpisy otagowane ‘mouseover’

Ruch na stronie z jQuery

wtorek, 15 Październik 2013

Nie będę pisał o tym, jak zwiększyć ruch na stronie w sensie ilości użytkowników odwiedzających serwis, tylko o wprowadzeniu ruchomych elementów reagujących na określone zachowania użytkownika. Skorzystam przy tym z dobrodziejstw JavaScriptu i biblioteki jQuery. Jeżeli nie znasz jQuery, przeczytaj Co mogę zrobić z jQuery?.

Efekt, którego realizację chcę tu przybliżyć, zaprezentowałem poniżej. Najedź myszą na kolejne grafiki. Dalej znajdziesz kolejne etapy jego realizacji.

Obraz 1.

Obraz 2.

Obraz 3.

Obraz 4.

Obraz 5.

Obraz 6.

Zaczniemy od kodu HTML:

<div id="photos">
<div class="photo">
 	<div class="text"><p>Obraz 1.</p></div>
 	<img src="img1.jpg" id="p1" />
</div>
<div class="photo">
 	<div class="text"><p>Obraz 2.</p></div>
 	<img src="img2.jpg" id="p2" />
</div>
<div class="photo">
 	<div class="text"><p>Obraz 3.</p></div>
 	<img src="img3.jpg" id="p3" />
</div>
<div class="photo">
 	<div class="text"><p>Obraz 4.</p></div>
 	<img src="img4.jpg" id="p4" />
</div>
<div class="photo">
 	<div class="text"><p>Obraz 5.</p></div>
 	<img src="img5.jpg" id="p5" />
</div>
<div class="photo">
 	<div class="text"><p>Obraz 6.</p></div>
 	<img src="img6.jpg" id="p6" />
</div>
</div>

Całość znajduje się w znacznikach div z identyfikatorem photos. W zależności od szerokości tego elementu w jednym wierszu znajdzie się większa lub mniejsza liczba grafik. Każda grafika składa się z dwóch części: górnej – widocznej od razu i dolnej – pokazującej się po najechaniu myszą. Do elementów img dodałem identyfikatory. Grafiki poprzedzone są opisami zawartymi w elementach div klasy text, a łącznie z grafiką w elementach div klasy photo. Te divy służą do ograniczenia widoczności grafik do połowy ich wysokości, co jest realizowane przez definicje styli CSS:

#photos
{
 	width: 750px;
 	margin: 20px auto;
}
.photo 
{
 	width: 350px;
 	height: 350px;
 	overflow: hidden;
 	display: inline-block;
 	position: relative;
}
img 
{
 	display: none;
 	position: relative;
 	top: 0px;
}
.text 
{
 	width: 100%;
 	height: 100px;
 	background: #fff;
 	position: absolute;
 	left: 0px;
 	bottom:-100px;
 	z-index: 100;
}

Div photos swoją szerokością ogranicza ilość grafik w wierszu. Klasa photo definiuje widoczny obszar dla każdego pliku graficznego do kwadratu o boku 350px. Właściwość overflow ustawiona na hidden ukrywa paski przewijania dla zawartości nie mieszczących się w zdefiniowanym obszarze, display: inline-block sprawia, że elementy tej klasy zachowują się na zewnątrz jak elementy liniowe (ustawiają się jeden za drugim), a wewnątrz są elementami blokowymi zachowującymi zdefiniowane wymiary. Pozycjonowanie relatywne pozwoli na użycie tych elementów jako odniesienia dla elementów zawartych wewnątrz nich. Elementy img początkowo nie są widoczne. Za ich pokazanie będzie odpowiedzialny odpowiedni kod jQuery. Pozycjonując te elementy będziemy mogli wpływać na ich wartość top liczoną względem zewnętrznego elementu pozycjonowanego relatywnie. Została nam jeszcze klasa text. Elementy tej klasy ze względu na to, że są mniejsze niż element nadrzędny są pozycjonowane absolutnie, czyli właściwość bottom odnosi się do dolnej krawędzi elementu nadrzędnego, a nie elementu klasy text. Ujemna wartość ukrywa tekst pod dolną krawędzią elementu klasy photo, a z-index z wartością 100 gwarantuje pojawianie się tekstu na, a nie pod grafiką.

Teraz ostatnia i najważniejsza część, czyli kod jQuery:

$(document).ready(function()
{
	$('#p1').fadeIn(1000);
 	$('#p2').delay(200).fadeIn(1000);
 	$('#p3').delay(400).fadeIn(1000);
 	$('#p4').delay(600).fadeIn(1000);
 	$('#p5').delay(800).fadeIn(1000);
 	$('#p6').delay(1000).fadeIn(1000);
 
 	$('.photo').mouseover(function()
 	{
 		if($('img',this).queue('fx').length==0)
		{
			$('img',this).animate({'top':'-350px'},500);
			$('div',this).delay(200).animate({'bottom':'0px'},800);
		}
 	});
 	$('.photo').mouseleave(function()
 	{
 		if($('img',this).queue('fx').length<2)
		{
			$('div',this).animate({'bottom':'-100px'},400);
			$('img',this).delay(200).animate({'top':'0px'},700);
		}
	});
});

Skrypt rozpoczynamy od pokazania kolejnych grafik z efektem fadeIn. Efekt dla każdego kolejnego obrazka odpala się z opóźnieniem 200 ms względem poprzedniego (funkcja delay() z argumentem o 200 wyższym od poprzedniego). Poniżej mamy obsługę dwóch zdarzeń: mouseover i mouseleave. W pierwszym przypadku mamy dwie animacje funkcją animate(). Najpierw przewijamy w górę grafikę, a potem tekst. Całość jest zawarta w instrukcji warunkowej, którą na razie pominę. Warto sprawdzić zachowanie skryptu bez instrukcji if przy jednym i drugim zdarzeniu. W mouseleave najpierw tekst wraca na miejsce początkowe (tuż pod dolną krawędź widocznego obszaru), a następnie grafika zjeżdża w dół.

Ponieważ w jQuery efekty animacji są kolejkowane, to wszystkie zdarzenia powodujące wywołanie animacji, będą dokładały te animacje do kolejki. Szybkie, kilkukrotne najechanie i opuszczenie kursorem myszy tej samej grafiki spowoduje utworzenie kolejki wielu efektów, które będą musiały być wykonane. Użytkownik nie będzie już nic robił, a obrazki będą się przesuwały w górę i w dół tyle razy, ile razy te efekty zostały wcześniej dodane do kolejki. Rozwiązaniem tego problemu jest kontrolowanie ilości efektów w kolejce, co umożliwia nam właściwość length obiektu queue. Właśnie tę funkcję realizują instrukcje warunkowe w obsłudze zdarzeń. W pierwszym przypadku nowe animacje będą dodane tylko w sytuacji gdy kolejka jest pusta. W drugim bierzemy pod uwagę fakt, że pierwsza faza może nie zostać zakończona, więc jeden efekt może jeszcze być obecny w kolejce.

Zaprezentowany w tym artykule przykład nie będzie działał poprawnie w przeglądarkach IE8 i wcześniejszych ze względu na użytą wartość display: inline-block, której wymienione przeglądarki nie obsługują. Jeżeli komuś zależy na tych przeglądarkach powinien wymienić display: inline-block na float: left. Możliwe, że będzie to wymagało dopracowania kilku innych szczegółów.