
Oto pierwsza część krótkich kursów, opisująca bliżej frameworki JavaScript. Pierwszym z nich będzie Prototype JS.
Framework Prototype JS – od podstaw
Garść wstępnych informacji opisujących Framework Prototype JS, pojawiła się już w artykule Frameworki JS – słowo wstępne.
Celem niniejszego artykułu nie jest zastąpienie dokumentacji, ale opis kluczowych elementów biblioteki, który wystarczy programiście do zrozumienia zasad i pozwoli swobodnie programować.
Może także stanowić „ściągawkę” dla już obeznanych z tym frameworkiem.
Do dzieła! Pobieramy bibliotekę, dodajemy do strony i już możemy z jej dobrodziejstw.
Tip: możemy także szybko dołączyć framework Prototype JS z CDN:
<script src="//ajax.googleapis.com/ajax/libs/prototype/1.7.1.0/prototype.js"></script>
Używając następującego kodu, sprawdzimy czy Prototype JS został załadowany:
if (typeof Prototype === "undefined") { throw new Error("Ten skrypt wymaga Prototype JS"); } // tudzież po prostu //if (typeof Prototype != "undefined") { // kod ... //}
Przejdźmy dalej.
Obiekt Element
Na początku powiemy o obiekcie Element, umożliwiającym operacje na elementach dokumentu.
Przykład – sprawdzanie, czy element jest widoczny:
function isHidden(item_name) { if ($(item_name).style.display == "none") return true; else return false; } alert(isHidden('foobar');
Element można ukryć / schować wygodnie, zamiast style.display używając metod show() i hide():
$('element_id').hide();
Funkcja update – aktualizacja elementu:
<div id="topSecret" style="display: none;">Niewidoczny</div>
// ... $('topSecret').update('Widoczny').show();
Jak widać, wywołania metod można w prosty sposób ze sobą łączyć.
Funkcje narzędziowe Prototype JS
Pora na magię framework’ów, czyli specjalne funkcje narzędziowe.
Funkcja $() – obudowana wersja getElementById(), można podać ID elementu jak i przekazać sam element, i odwoływać się do niego.
Funkcję $() spotkamy nie tylko we framework’u Prototype JS – jest często spotykana w innych rozwiązaniach tego typu.
Przykład – użycie funkcji $():
// ukryj wybrane elementy: $('item1', 'item2', 'item3').invoke('hide');
Możemy podać zarówno jeden jak i kilka nazw (ID) elementów. Metoda invoke() z obiektu Enumerable natomiast, służy do wywołania danej akcji dla wszystkich podanych elementów.
Funkcja $$() – podwójne $$ – pozwala wybierać elementy według klas CSS, odbywa się to w postaci:
$$('element');
Przykłady – użycie funkcji $$():
// wszystkie elementy typu div; to samo co użycie // document.getElementsByTagName('div') $$('div'); $$('#content'); // to samo co $('content'), zwraca tablicę $$('li.foobar'); // pobiera wszystkie elementy LI z klasą foobar
Pseudo-elementy (od wersji 1.5.1+)
Czyli składnia rozszerzona, pozwalająca na dostęp do przeróżnych elementów, używając zwięzłej składni zamiast rozbudowanego kodu.
Przykłady – użycie pseudo-elementów:
Przykładowa struktura HTML:
<div id="content"> <p id="par1">Dane testowe.</p> <a href="www.foobar.com">Link 1</a> <a href="www.foo1.com" rel="nofollow">Link 2</a> <a href="www.foo2.com" rel="start">Link 3</a> <a href="#" rel="start">Link 4</a> </div>
Obsługa w JavaScript i Prototype JS:
// pobierz kolekcję linków będących wewnątrz elementu // od id = "content", mających atrybut rel $$('#content a[rel]'); // wszystkie linki, których atrybut href ma wartość "#" $$('a[href="#"]'); // wszystkie linki (element a) wewnątrz elementu // z id = "navbar" lub "content" $$('#navbar a', '#sidebar a');
Gdy się temu przyjrzymy dostrzeżemy możliwości jakie dostajemy, oraz oszczędność czasu, wystarczy tylko opanować używanie tego typu składni.
Przykłady zaawansowane:
// pobierz tylko pola tekstowe $('input[type="text"]') // wszystkie linki, oprócz (~=) tych zawierających // "nofollow" w atrybucie rel $$('a:not([rel~=nofollow])'); // wszystkie parzyste wiersze w tabelach $$('table tbody > tr:nth-child(even)'); // puste elementy div (bez tesktu, tylko białe znaki, itp) $$('div:empty'); // pobieranie względem położenia // wszystkie dzieci elementu ul z id = menu $$('ul#menu > li') // negacja $$('ul#menu li:not(.current)') // elementy nie posiadające atrybutu rel $$('ul#menu a:not([rel])')
Pseudo-elementy to naprawdę świetne narzędzie.
Wróćmy teraz do dalszego poznawania funkcji narzędziowych.
Funkcja $F()
Służy ona do odczytywania wartości elementu formularza, jak input, select, itd.
Przykład – prosta obsługa formularza:
// w prosty sposób odczytamy wartość listy var value = $F( "lista_testowa_id" );
Funkcja $A()
Kopiuje lub konwertuje dowolną listę (jak childnodes), na obiekt typu Array, przez co umożliwia szybszy dostęp do poszczególnych elementów tablicy.
Przykład – użycie funkcji $A():
function showOptions() { var someNodeList = $('lstEmployees'). getElementsByTagName('option'); var nodes = $A(someNodeList); nodes.each(function(node) { alert(node.nodeName + ': ' + node.innerHTML); }); }
Otrzymujemy kolekcję z danymi pobranymi z elementu HTML (np. pola typu Select). Kolejny przykład tworzy kolekcję zawierającą paragrafy (elementy <p>) dokumentu.
Przykład #2:
var paras = $A(document.getElementsByTagName('p')); paras.each(Element.hide); $(paras.last()).show();
Jeszcze bardziej interesująca może być kolejna funkcja.
Funkcja $H()
Przekształca argument na hash implementujący tablicę asocjacyjną, np.:
var testowyObiekt = { width: 100, height: 100, depth: 20 }; var testowyHash = $H( testowyObiekt ); var wynik = testowyHash.toQueryString(); alert(wynik);
Kolekcje danych i Enumerable
Znów mała przerwa w omawianiu funkcji narzędziowych.
Kolekcje danych – w Prototype JS korzystamy z faktu, że dziedziczą one z Enumerable, więc możemy użyć przetwarzania dedykowanego.
Przykładem jest each:
$( "a1", "b2", "c" ).each(function(item, index) { alert(item + " znajduje się pod indeksem " + index); item.style.width = 180; });
Jak widać otrzymujemy przyjemny w użyciu iterator.
Idźmy dalej.
Funkcja $R()
Funkcja ta daje programiście zwięzły sposób zapisu instrukcji new (argumenty: lowerBound, upperBound, excludeBounds), która reprezentuje zakres wartości ograniczony argumentami dolnej i górnej granicy, dla tworzonej tablicy:
var zasieg = $R(20, 100, false); zasieg.each(function(value, index) { alert("Wynik dzialania" + value); }); $A($R('aa', 'ah')).join(', '); // aa, ab, ac, ad, ae, af, ag, ah $R(0, 10, true).include(10) // false $R(0, 10, true).each(function(value) { // invoked 10 times for value = 0 to 9 });
Funkcja $w()
Przekształca string w tablice, jak qw(foo bar) w języku Perl:
$w(String) -> Array
Przykład – użycie funkcji $W():
$w('apples bananas kiwis') // ['apples', 'bananas', 'kiwis'] $w('ads navbar funkyLinks').each(Element.hide); // ukryj te elementy
Pora na coś specjalnego.
Funkcja Try.these()
Pomaga nam przy różnicach w implementacji dla przeglądarek (szuka najlepszego wariantu).
Przykład – użycie funkcji Try.these() – crossbrowser support:
createXMLHttp: function() { return Try.these( function() { return new XMLHttpRequest() }, function() { return new ActiveXObject('Msxml2.XMLHTTP') }, function() { return new ActiveXObject('Microsoft.XMLHTTP') } ) || false; }
Events – obsługa zdarzeń
Framework Prototype JS daje nam wygodną obsługę zdarzeń. Jej podstawą jest obiekt Event.
Przykład – obsługa zdarzenia pojawienia się kursora myszy nad elementem o ID „foobar”:
Event.observe('foobar', 'mouseover', function() { alert('Mysz!'); });
Można powiedzieć, że zarejestrowaliśmy tutaj obserwator (observer) reagujący w dany sposób na określone zdarzenie (event) dla danego elementu.
Kolejny przykład to obsługa zdarzenia wczytania dokumentu (strony):
Event.observe(window, 'load', function() { // ... });
AJAX i Framework Prototype JS
Prototype JS jest znakomitym frameworkiem również jeśli chodzi o wspieranie pracy z Ajax. Izoluje poziom implementacji od konkretnej przeglądarki, dając nam do ręki wygodne narzędzia pracy z Ajax.
Ajax.Updater – czyli wywołanie Ajax z odświeżeniem elementu strony.
Posiada dodatkowe opcje:
– evalScripts (default false)
– insertion (’top', 'bottom', 'before', 'after')
Przykład – Ajax.Updater():
new Ajax.Updater('items', '/items', { parameters: { text: $F('text') }, insertion: Insertion.Bottom });
Przykład 2:
function _updateX(tmp_id) { new Ajax.Updater('id2', '/module/action, { asynchronous: true, evalScripts: true, parameters:{ id: tmp_id } }); }
Drugi argument (module / action) to adres do zasobu po stronie serwera, który odbierze (żądanie) request.
Zdefiniowanie zdarzeń success oraz failure:
function testAjax() { new Ajax.Updater({ success: 'newsContent', failure: 'errors' }, '/prototypejs/data', { method: 'post', insertion: Insertion.Top }); }
Ajax.Request – to kolejne, podobne do Updater() narzędzie; użyjemy do szczególnie tam, gdzie nie koniecznie chcemy zaktualizować element strony.
Przykład – użycie Ajax.Updater():
// plik ajax.js alert('witaj!'); // wywołanie new Ajax.Request('my_ajax.js', { method: 'get' });
Przykład #2:
function testAjax() { new Ajax.Request('/prototypejs/data', { method: 'get', onSuccess: function(transport) { $('news').innerHTML = transport. responseText || "brak danych"; }, onFailure: function() { alert('Wystąpił błąd podczas pobierania danych') } }); }
Dostęp do JSON
W opisywanym ostatnio artykule o JSON pisaliśmy o podstawowej obsłudze formatu JSON w JavaScript. Framework Prototype JS daje nam swoje sposoby w zestawie.
Przykład – framework Prototype JS i użycie JSON:
new Ajax.Request('/some_url', { method: 'get', requestHeaders: { Accept: 'application/json' }, onSuccess: function(transport) { var json = transport.responseText.evalJSON(true); } });
Zdefiniowaliśmy tu nowy rodzaj parametru: requestHeaders. Odnosi się on do nagłówka żądania, a w naszym przykładzie określa typ akceptowalnych danych (JSON).
Przekazanie parametrów możemy wykonać w następujący sposób:
function testAjax() { var url = "/prototypejs/data"; var params = new Object(); params.method = "get"; params.parameters = "osoba = Jan"; params.onComplete = putText; params.onFailure = showErrorMsg; new Ajax.Request(url, params); }
Jeśli chcemy przekazać parametry, używamy właściwości postBody.
Przykład – przekazanie argumentów żądania poprzez postBody:
new Ajax.Request('/foo/bar', { method: 'post', postBody: 'thisvar=123&thatvar=Xyz' });
Natomiast evalScripts ustawiona na true, wykona skrypty blokach <script> </script>
Przykład – nakazanie wykonania kodu JS:
newAjax.Updater('mydiv', '/foo/bar', { asynchronous: true, evalScripts: true });
Periodyczna aktualizacja fragmentu strony – PeriodicalUpdater.
Jest to ciekawe i przydatne rozwiązanie od twórców Prototype JS. Dzięki niemu możemy nakazać wykonywanie żądania Ajax co określony czas (wszystko łatwo definiowalne poprzez parametry).
Przykład – zastosowanie Ajax.PeriodicalUpdater:
function testAjax() { new Ajax.PeriodicalUpdater('dyn_content', '/action/data', { // insertion: bottom, etc... method: 'get', frequency: 3, decay: 2 }); }
A na koniec przykład definicji globalnych.
Przykład – użycie Ajax.Responders
// insertion: bottom, etc ... Ajax.Responders.register({ onCreate: showLoader, onComplete: hideLoader });
Tym samym wykonaliśmy rejestrowanie funkcji do wszystkich wywołań AJAX.
Wspólne opcje Ajax (common options) – bardziej szczegółowy i aktualny opis dla nich znajdziemy w dokumentacji.
Podsumowanie
Dotarliśmy wreszcie do końca części I kursu traktującego o framework’u Prototype JS. Być może jest nieco dłuższa niż inne artykuły, ale w końcu poruszamy dość rozbudowany temat.
Zapraszam do kolejnych części i kolejnych kursów, które pojawią się wkrótce. Dziękuję za uwagę.