Praktyczne wprowadzenie do JavaScript #5

Nasz dokument HTML, nad którym pracujemy od czterech lekcji, przeobraził się w całkiem zgrabne kaczątko, nie urażając oczywiście zwolenników jakiejkolwiek frakcji politycznej. Używając jednego kliknięcia myszy, odwiedzający naszą stronę może natychmiast odsłonić rozszerzoną treść newsa. Co jednak z tymi, którym nie chce się klikać?

Oczywiście głęboko naciągam sytuację, ale życie, jak to życie, stawia przed nami nieustanne niespodzianki. Załóżmy więc, że nasz szef/babcia/sprzątaczka albo po prostu my sami chcemy zadbać o leniwych użytkowników i udostępnić im funkcjonalność znaną z poprzednich odcinków poprzez najechanie kursorem myszy na link więcej.

Jak się pewnie domyślasz, całość funkcjonować będzie na podobnych zasadach, jak onclick. Z tą różnicą, że my chcemy rozpoznać zdarzenie, kiedy użytkownik najedzie kursorem myszy na link, a nie to, kiedy na niego kliknie. Naturalne w tym wypadku wydaje się zastąpienie onclick czymś innym. I tutaj z pomocą przychodzi nam funkcja, obsługująca zdarzenie najechania myszką na jakiś element HTML, a jest nią onmouseover. Dla znających angielski zapewne nie jest to zaskoczenie, bo, tłumacząc tę nazwę wiemy już, za co funkcja będzie odpowiedzialna.

Jako że w zaistniałej sytuacji onclick nam się nie przyda, zastąpmy go funkcją, o której przed chwilą wspomniałem.

<a href="#" onmouseover="PokazAkapit('more');" id="link">więcej</a>

W ten oto sposób, biorąc pod uwagę, że używamy funkcji PokazAkapit() z poprzedniej części, zdecydowaliśmy, że uruchomimy ją po najechaniu kursorem myszy na link więcej. Jako argument tej funkcji wpisałem more. Oznacza to więc, że będziemy pokazywać i zwijać paragraf o id=”more”. Drugi akapit o id=”more_second” niech zostanie i czeka na swoją kolej.

Nasz dokumencik wygląda obecnie tak:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="pl-PL">
<head>
<title>Strona z newsem</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf8" />

<!-- Nasz kod Javascript: -->

<script type="text/javascript">

	function PokazAkapit(id_paragrafu)
	{
		var akapit = document.getElementById(id_paragrafu);
                var odnosnik = document.getElementById('link');

		var view = akapit.style.display;

                if (view == "block")
		{
                        odnosnik.innerHTML = "więcej";
			akapit.style.display = "none";
		}

		if (view == "none")
		{
                         odnosnik.innerHTML = "schowaj";
			akapit.style.display = "block";
		}

	}

</script>

</head>
<body>
<div>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Pellentesque metus eros, rutrum at, hendrerit nec, posuere ac.<a href="#" onmouseover="PokazAkapit('more');" id="link">więcej</a></p>

<p id="more" style="display: none;">Vivamus pretium fringilla metus. Praesent a enim eu metus scelerisque tincidunt. In auctor lorem et leo.</p>

<p id="more_second" style="display: none;">Vivamus pretium fringilla metus. Praesent a enim eu metus scelerisque tincidunt. In auctor lorem et leo.</p>
</div>
</body>
</html>

Najedźmy teraz kursorem na więcej i zaobserwujmy, co się stało. Otóż sytuacja jest co najmniej dziwna, bowiem po pierwszym najechaniu akapit pokazuje się, by po drugim najechaniu schować się.

Łatwo jednak możemy wytłumaczyć tę sytuację. By lepiej zrozumieć zaistniałe fakty, spójrzmy po raz kolejny na funkcję PokazAkapit:


function PokazAkapit(id_paragrafu)
	{
		var akapit = document.getElementById(id_paragrafu);
		var odnosnik = document.getElementById('link');

		var view = akapit.style.display;
		if (view == "block")
		{
		
			odnosnik.innerHTML = "więcej";
			akapit.style.display = "none";
		}

		if (view == "none")
		{
			odnosnik.innerHTML = "schowaj";
			akapit.style.display = "block";
		}

	}

Analizując podany wyżej kod od góry do dołu, stwierdzamy, że najpierw pobierana jest wartość display (var view = akapit.style.display;) wybranego paragrafu, którego id przekazujemy jako argument. W zależności od tej wartości (if (view == „block”), if (view == „none”)), ustawiana jest nowa (akapit.style.display = „none”;, akapit.style.display = „block”;). Zresztą to już wiemy z poprzednich odcinków. Ważne jest natomiast logiczne połączenie tego z nowopoznaną funkcją onmouseover. Symulując w myślach działanie tego duetu (onmouseover i PokazAkapit) stwierdzamy, że po pierwszym najechaniu kursorem wykonuje się drugi warunek (if (view == „none”)), a po drugim najechaniu pierwszy (if (view == „block”)).

To, czym dysponujemy jest całkiem sympatyczne, ale mimo wszystko zdaje się, że można jeszcze coś ulepszyć. Jest to prawda, bowiem czy nie lepszym efektem byłoby pokazywać paragraf po najechaniu kursorem myszki na link, a po jego zwolnieniu ukrywać akapit?

Wiemy już, co jest odpowiedzialne za wykonywanie kodu po najechaniu kursorem na jakikolwiek tag HTML w <body></body>. Za zwolnienie kursora odpowiada natomiast dość analogiczna funkcja (przynajmniej w nazewnictwie), jaką jest onmouseout.

Żeby więc dodać możliwość schowania paragrafu po zwolnieniu kursora z więcej, należy, analogicznie do naszego postępowania z onmouseover, dodać co nieco do ciała naszego linku:

<a href="#" onmouseover="PokazAkapit('more');" onmouseout="" id="link">więcej</a>

Dodaliśmy następujący kod:

onmouseout=""

Tym sposobem informujemy przeglądarkę, aby wykonała kod pomiędzy cudzysłowami w chwili, gdy zwolnimy kursor z danego tagu, w tym przypadku jest to link <a>. Oczywiście, by w ogóle do tego doszło, najpierw należy naturalnie najechać kursorem na dany element.

Podstawiając zmodyfikowany link więcej do dokumentu, możemy stwierdzić, że stoimy nadal w miejscu. I jest to słuszna uwaga, ponieważ po najechaniu kursora wykonuje się niezmiennie funkcja PokazAkapit, a po jego zwolnieniu nie dzieje się w zasadzie nic. Przyczyną tego faktu jest, jak zapewne zauważyłeś, brak jakichkolwiek instrukcji w onmouseout. Dodajmy je, uprzednio wzbogacając kod jednym kawałkiem, pokazującym, że to w ogóle działa:

onmouseout="alert('Własnie zwolniles kursor myszy z linku wiecej');"

Najedźmy teraz kursorem na link, aby stwierdzić, że wszystko jest w porządku. Po umieszczeniu kursora na linku, wykonuje się PokazAkapit, która zmienia wartość linku oraz, oczywiście, display paragrafu. Gdy zwolnimy kursor, pokaże się nam okienko, zgodnie z tym, co przed chwilą dodaliśmy:

alert('Własnie zwolniles kursor myszy z linku wiecej');

Jesteśmy w połowie drogi. Skoro po najechaniu myszką paragraf musi się tylko pokazać, funkcja PokazAkapit jest wobec tego nieużyteczna, ponieważ obsługuje i pokazywanie, i chowanie paragrafu. Rozdzielmy więc ją na dwie suwerenne funkcje. Pierwsza będzie odpowiadać za pokazywanie dowolnego akapitu, druga za jego schowanie. Nazwijmy je PokazAkapit oraz SchowajAkapit. Skasujmy też bez obaw wszystko, co jest pomiędzy <script type="text/javascript"></script>, umieszczając nasze dwie perełki:



<script type="text/javascript">
	function PokazAkapit(id_paragrafu)
	{
		var akapit = document.getElementById(id_paragrafu);
		var odnosnik = document.getElementById('link');

		
		odnosnik.innerHTML = "schowaj";
		akapit.style.display = "block";
	}

	function SchowajAkapit(id_paragrafu)
	{
		var akapit = document.getElementById(id_paragrafu);
		var odnosnik = document.getElementById('link');

		odnosnik.innerHTML = "więcej";
		akapit.style.display = "none";
		
	}
</script>

Jak widzimy, mamy do dyspozycji dwie, całkiem nowe funkcje. Ich wnętrze zostało uboższe o zmienną view oraz instrukcje if { }. Zmiennej nie ma, ponieważ nie sprawdzamy wartości display akapitów, tylko od razu ją zmieniamy (akapit.style.display = „none”;, akapit.style.display = „block”;). Ifów nie ma w zasadzie z tego samego powodu – jako że każda z funkcji odpowiedzialna jest tylko za jedną rzecz, nie ma potrzeby sprawdzać wartości display. PokazAkapit pokazuje wybrany akapit i niepotrzebna jest jej wiedza, czy akapit ten jest nadal pokazany, czy schowany. Podobnie jest z SchowajAkapit. Nie musimy więc układać żadnych warunków, od których zależy, co funkcje te zrobią.

Spójrzmy teraz na nasz cały dokument HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="pl-PL">
<head>
<title>Strona z newsem</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf8" />

<!-- Nasz kod Javascript: -->

<script type="text/javascript">
	function PokazAkapit(id_paragrafu)
	{
		var akapit = document.getElementById(id_paragrafu);
		var odnosnik = document.getElementById('link');

		
		odnosnik.innerHTML = "schowaj";
		akapit.style.display = "block";
	}

	function SchowajAkapit(id_paragrafu)
	{
		var akapit = document.getElementById(id_paragrafu);
		var odnosnik = document.getElementById('link');

		odnosnik.innerHTML = "więcej";
		akapit.style.display = "none";
		
	}
</script>

</head>
<body>
<div>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Pellentesque metus eros, rutrum at, hendrerit nec, posuere ac.<a href="#" onmouseover="PokazAkapit('more');" onmouseout="" id="link">więcej</a></p>

<p id="more" style="display: none;">Vivamus pretium fringilla metus. Praesent a enim eu metus scelerisque tincidunt. In auctor lorem et leo.</p>

<p id="more_second" style="display: none;">Vivamus pretium fringilla metus. Praesent a enim eu metus scelerisque tincidunt. In auctor lorem et leo.</p>
</div>
</body>
</html>

Wypróbujmy teraz jego działanie. Okazuje się, że te jest niezmienne. Paragraf pojawia się, ale nie chce zniknąć. Ano, tak! Zapomnieliśmy dać znać linkowi, że po zwolnieniu kursora ma się wykonać schowanie wybranego akapitu. Uzupełniamy więc

onmouseout=""

o to:

onmouseout="SchowajAkapit('more');"

Zupełnie analogicznie do:

onmouseover="PokazAkapit('more');"

Wypróbujmy efekt naszej pracy. Wreszcie mamy to, co sobie zamierzyliśmy na początku!

Tradycyjnie, ujrzyjmy pełny dokument HTML, który powstał:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="pl-PL">
<head>
<title>Strona z newsem</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf8" />

<!-- Nasz kod Javascript: -->

<script type="text/javascript">
	function PokazAkapit(id_paragrafu)
	{
		var akapit = document.getElementById(id_paragrafu);
		var odnosnik = document.getElementById('link');

		
		odnosnik.innerHTML = "schowaj";
		akapit.style.display = "block";
	}

	function SchowajAkapit(id_paragrafu)
	{
		var akapit = document.getElementById(id_paragrafu);
		var odnosnik = document.getElementById('link');

		odnosnik.innerHTML = "więcej";
		akapit.style.display = "none";
		
	}
</script>

</head>
<body>
<div>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Pellentesque metus eros, rutrum at, hendrerit nec, posuere ac.<a href="#" onmouseover="PokazAkapit('more');" onmouseout="SchowajAkapit('more');" id="link">więcej</a></p>

<p id="more" style="display: none;">Vivamus pretium fringilla metus. Praesent a enim eu metus scelerisque tincidunt. In auctor lorem et leo.</p>

<p id="more_second" style="display: none;">Vivamus pretium fringilla metus. Praesent a enim eu metus scelerisque tincidunt. In auctor lorem et leo.</p>
</div>
</body>
</html>
W związku z różną interpretacją kodu przez przeglądarki, warto dodać naszemu linkowi więcej style display=”block”. Zabezpieczy to nas na 100% przed potencjalnymi, dziwnymi zachowaniami przeglądarek (np. Opera 9), związanymi z chowaniem się akapitu.

Podsumujmy więc.

Znamy następujące zdarzenia, które można wstawić jako atrybut do tagów HTML:

Komentarze

1

Bardzo, bardzo podobają mi się te artykuły. Ja, twardogłowy z JS zaczynam wszystko rozumieć :)

Pozdrawiam. Mam nadzieję, że nie zaprzestaniesz :)

2

nie dziala poprawnie w O9.21 :/

Pj
3

To przez linka, pomaga ruszanie intensywne myszka, badz nadanie linkowi display: block;.

4

Opera 9.22 i ukrywanie paragrafu przy nadaniu linkowi display: block; faktycznie jakoś się „rwie” (onmouseover załapuje dopiero za którymś razem). Znasz może przyczynę takiego zachowania (bug Opery czy co)? Pod Fx i IE śmiga. Aha – dodanie do linka display: block; powoduje też kolejną niedogodność – odnośnik „schodzi” linijkę niżej (poniżej paragrafu), co nie prezentuje się za dobrze. Dało by się jakoś sprawę obejść tak, aby pod flagowymi przeglądarkami działało to w porządku, a dodatkowo wyglądało po ludzku? :)

m010ch
5

m010ch: Z tego, co widze, to jest to bug Opery. Ani na czystym JS w roznych konfiguracjach nie dziala to na Operze, ani uzywajac jQuery. Splodze o tym chyba jakas notke, a sam przyklad w kursie nieco zmodyfikuje.

Pozdrawiam

6

dlaczego nie zostawić kod z jedną funcką PokazAkapit(”) i poprostu zapisać odnośnik ? Działa tak samo.

avatar
7

sory miało być a href=”#” onmouseover=”PokazAkapit(‚more’);” onmouseout=”PokazAkapit(‚more’);” id=”link”

avatar
8

@avatar: zgadza się, działa tak samo, ale co się stanie jeśli najedziesz myszą na link (akapit się rozwinie), następnie odsuniesz kursor znad linku ale tego zdarzenia przeglądarka nie wychwyci (z jakiegoś powodu, np.: utrata focusa na rzecz innego programu, czy chwilowe niedomaganie systemu :]) a potem znów najedziesz na link myszką. Drugie najechanie myszką będzie wtedy gdy akapit już jest rozwinięty (ma style.display = block), więc funkcja go ‚przełączy’, czyli schowa (style.display = none), w efekcie przez niewychwycenie jednego zdarzenia przez przeglądarkę zacznie to wszystko się zachowywać odwrotnie

Bishop
9

Fajny kurs ale brakuje mi przykładów żeby można było od razu zobaczyć na tej stronie jak to działa

kajek
10

I kolejny krok naprzód ;)

Dodaj komentarz

Dozwolone tagi: <blockquote>, <code>, <strong>