Kurs: Prototype JS w pigułce. Cz. 2.

Prototype JS

Poziom średnio-zaawansowany

Witam w kontynuacji poprzedniego artykułu – Kurs Prototype JS w pigułce. Dziś skupimy się na elementach dokumentu i wykonywaniu na nich operacji.

Krok dalej we framework Prototype JS

W tej części kursu zobaczymy pracę z DOM w wydaniu Prototype JS. Przejdźmy zatem od razu do omawiania kolejnych zagadnień tej biblioteki.

Obiekt Template

Pozwala nam uzyskać coś w rodzaju interpolacji; w JavaScript jest to wygodne narzędzie wspomagające prezentację danych, np. po ich otrzymaniu z sieci i przetworzeniu.

Przykład – użycie obiektu Template:

var cart = new Object();
cart.items = [];
cart.items.push({ product: 'Book', price: 24.50, quantity: 1 });

cart.items.push({ product: 'Pencils', price: 5.44, quantity: 3 });

var itemFormat = new Template (
    'You are ordering #{quantity} units ' + 
    'of #{product} at $#{price} each' );

var formatted = '';

for (var i = 0; i < cart.items.length; i++) {
    var cartItem = cart.items[i];
    formatted += itemFormat.evaluate(cartItem) + '<br/>\n';
}

Po bliższych oględzinach zauważymy jak fajny jest to przykład możliwości. Definiujemy format, w jakim będą wyświetlane dane (zmienna itemFormat) a następnie iterujemy po zdefiniowanych danych (w kolekcji items) aby wydobyć dane, które zostaną podstawione w odpowiednich miejscach.

Przykład 2 – użycie Template do budowania elementów URL:

var hx = new Template('show.php?lang=#{lang}&cat=#{mycat}&x=#{x}');
var selection = { my_cat: 'books' , lang: 'en' };
hx.evaluate(selection); // 'show.php?lang=en&cat=books&x='

W obiekcie selection brakuje klucza „x” – po prostu zostanie pominięty podczas przetwarzania szablonu, więc nie zostanie podstawiona żadna wartość w „&x=”.

Inne spojrzenie na tablice

Poznaliśmy już obsługę tablic w „czystym” JavaScript. Prototype JS daje nam dodatkowe możliwości obsługi tablic, tudzież upraszcza standardowe metody.

Zacznijmy od iteracji.

Implementacja wzorca iterator, służy w uproszczeniu do przechodzenia po kolejnych elementach (zbioru, obiektu czy też tablicy).

Przykład – iterowanie z użyciem each():

var myArray = new Array('A', 'B', 'C', 'D');

myArray.each(function(item) {
    // kod pracujący na poszczególnym (bieżącym) elemencie
    alert(item);
});

// Przypadek 2: iteracja po elementach HTML:
//var elements = $$('.menu-item');

//elements.each(function(element) {
  // ...
//});

Metody związane z Array dostarczane przez Prototype JS

– clear() – kasuje zawartość tablicy

– clone() – klonowanie tablicy

var two = mytab.clone(); // 'mytab' zostanie sklonowana w 'two'

– compact() – zwraca nową wersję tablicy, bez wartości null / undefined

– each() – iterator

– first() – zwraca pierwszy element tablicy

– flatten() – transformacja na tablice 1-D , np.:

['al', ['bob', 'lisa']].flatten(); // ['al', 'bob', 'lisa']

– from() – alias metody $A()

– indexOf() – indeks elementu

– inspect() – zwraca string zorientowany na debug

– last() – ostatni element, przeciwieństwo first()

– reverse() – odwracanie

– size() – rozmiar, podobnie jak natywny .length

– toArray() – konwersja na tablicę, np.:

var str = 'a, b, c';
alert(string.toArray());

alert($R(1, 5).toArray()); // [1, 2, 3, 4, 5]

– toJSON() – przekształcenie na JSON, np.:

['a', {b: null}].toJSON(); // '["a", {"b": null}]'

– uniq() – usuwa duplikaty z tablicy

– without() – zwraca tablicę z pominięciem określonych wartości, np.:

[5, 6, 1, 20].without(20, 6) // -> [5, 1]

Class i programowanie obiektowe OOP z pomocą Prototype JS

Omawialiśmy już OOP w JavaScript, Prototype JS daje nam kolejne możliwości.

Operacje na „klasach” mogą odbywać się według schematu jak w poniższym przykładzie:

var Klasa = {}; // ...

// addMethods - dodanie metod
Klasa.addMethods({
    speak: function() {
        // alert(this.name);
        alert('Hello!');
    }
});

Tworzenie „klasy” (warstwa z Prototype JS) – służy do tego metoda create():

create([superclass][, methods…]);

Parametr superclass określa klasę nadrzędną, natomiast do rodzica odwołujemy się poprzez $super, przez co dość łatwo uzyskujemy możliwość implementacji dziedziczenia.

Przykład – użycie Class.create():

var Animal = Class.create({
    initialize: function(name, sound) {
        this.name  = name;
        this.sound = sound;
    },

    speak: function() {
        alert(this.name + " says: " + this.sound + "!");
    }
});

// "wyprowadzamy" zwierzę z klasy Animal:
var Snake = Class.create(Animal, {
    initialize: function($super, name) {
        $super(name, 'hissssssssss');
    }
});

var ms = new Snake("Python");
ms.speak(); // "Python says: hissssssssss!"

var snake2 = new Snake("Boa");
snake2.speak(); // "Boa says: hissssssssss!"

// wbudujmy tu jeszcze Enumerable
var AnimalPen = Class.create(Enumerable, {
    initialize: function() {
    var args = $A(arguments);
        if (!args.all(function(arg) { 
            return arg instanceof Animal 
        }))
        throw "Only animals in here!"

        this.animals = args;
    },

    // implementacja _each aby używać metod z Enumerable
    _each: function(iterator) {
        return this.animals._each(iterator);
    }
});

var snakePen = new AnimalPen(ms, snake2);
snakePen.invoke('speak'); // invoke - wywołanie metody
// alert: "Python says: hissssssssss!"
// alert: "Boa says: hissssssssss!"

Mnie osobiście takie podejście do OOP w JavaScript, wspomagane przez framework Prototype JS, jak najbardziej odpowiada.

Zajmijmy się teraz elementami dokumentu i zobaczmy jakie ciekawe narzędzia daje nam Prototype JS.

Obiekt Element – głębsze spojrzenie

Obiekt element zaprezentowany został już w pierwszej części kursu. Teraz rozwiniemy ten temat.

A na początek Element jako konstruktor.

Przykład:

var a = new Element('a', { 'class': 'foo', href: '/file.htm' })
        .update("Next page");

Zostanie stworzony odnośnik na bazie podanych parametrów.

Krok dalej: Element, Prototype JS i rozszerzanie DOM poprzez metodę extend().

Przykład – dynamiczne tworzenie elementu:

var my_div = document.createElement('div');
Element.extend(my_div);
my_div.addClassName('pending').hide();
document.body.appendChild(my_div);

Tip: wskazówka cross-browser dla starszych wersji:

$('someElement').parentNode.hide(); // błąd w IE
$($('someElement').parentNode).hide(); // cross-browser

Metody z obiektu Element:

– absolutize() – nadaje position absolute

– addClassName() – dodanie klasy, np.:

$('divek').addClassName('klasa');

– addMethods() – addMethods([methods]) lub addMethods(tagName, methods), przykładowo:

var MyUtils = {
    truncate: function(element, len) {
        element = $(element);
        return element.update(element.innerHTML.truncate(len));
    },
    updateAndMark: function(element, html) {
        return $(element).update(html).addClassName('updated');
    }
}
Element.addMethods(MyUtils);

// try it:
$('explanation').truncate(100);

– ancestors() – pobiera przodków elementu, np.:

<div id="father"><div id="kid"></div></div>
$('kid').ancestors();
// wynik: [div#father, body, html]

– childElements() – dzieci elementu, depth = 1

– classNames() – zwraca tablicę z klasami elementu, np.:

$('divek').classNames(); // ['apple', 'fruit', 'food']

– cleanWhitespace() – czyści białe znaki

– clonePosition() – clonePosition(element, source[, options]), zwraca nowy HTMLElement

– cumulativeOffset() – skumulowana wartość offsetu elementu – x, y

– cumulativeScrollOffset() – offset w przypadku przewijania (zagnieżdżone elementy)

– descendantOf() – czy element jest potomkiem danego przodka, np.:

$('divek1').descendantOf('divek-foobar');
// true - 'divek' 1 jest potomkiem (zawiera sie w)

– descendants() – zwraca potomków jako tablicę

– down() – następny w dól, np.:

$(element).down(1).next('li', 2).hide();

– empty() – sprawdza czy element jest pusty, dla samych whitespaces da true

– extend() – extend(element) – rozszerza element o metody z Element.Methods oraz Element.Methods.Simulated

– fire() – tworzy niestandardowe zdarzenia o podanej nazwie, a następnie uruchamia go w danym elemencie

– firstDescendant() – tzw. pierwszy potomek, na przykład:

<div id="australopithecus">
  <div id="homo-erectus"><!-- This is cool -->
    <div id="homo-neanderthalensis"></div>
    <div id="homo-sapiens"></div>
  </div>
</div>
$('australopithecus').firstDescendant(); 
// div#homo-erectus

$('homo-erectus').firstChild; 
// comment node "This is cool"

$('homo-erectus').firstDescendant(); 
// div#homo-neanderthalensis

– getDimensions() – rozmiary – wartości width, height, np.:

$('rectangle').getDimensions(); // {width: 200, height: 100}

– getElementsByClassName() – elementy z daną klasą:

$('divek').getElementsByClassName('nazwa');

– getElementsBySelector() – wybiera elementy po selektorze, przykładowo wg zadanej wartości dla title:

<li id="golden-delicious" title="yummy!">Golden Delicious<li>
$('apples').getElementsBySelector('[title="yummy!"]');

– getHeight() – pobiera wartość height (wysokość) elementu

– getOffsetParent() – element najbliższego przodka

– getStyle() – pobieranie aktualnego stylu elementu:

$(element).getStyle('font-size');

– getWidth() – pobiera width (szerokość) elementu

– hasClassName() – czy element ma klasę, np.:

$('divek').hasClassName('lol');

– hide() – ukryj element

– identify() – zwraca atrybut ID elementu (jeśli istnieje)

– immediateDescendants() – bezpośredni potomkowie

– insert() – dodawanie nowego elementu; insert(element, { position: content })
lub insert(element, content)

– inspect() – łańcuch zorientowany na debug (więcej informacji)

– makeClipping() – wykonuje kadrowanie elementu, np. div’a z obrazkiem:

$('zdjecie').makeClipping().setStyle({ 
    width: '100px', height: '100px' 
});

– makePositioned() – pozycja relative

– match() – sprawdza dopasowanie: match(element, selector), np.:

<ul id="fruits">
  <li id="apples">
  <ul>
    <li id="golden-delicious">Golden Delicious</li>
    <li id="mcintosh">McIntosh</li>
  </ul>
  </li>
</ul>
$('fruits').match('ul'); // true
$('macintosh').match('li#macintosh.yummy'); // true
$('fruits').match('p'); // false

– next() – następny węzeł równorzędny (rodzeństwo)

– nextSiblings() – następne węzły równorzędne (rodzeństwo)

– observe() – obserwacja obiektu / elementu czyli obsługa zdarzeń, przykładowo:

$(element).observe('click', function(event) {
    alert(Event.element(event).innerHTML);
});

– positionedOffset() – offsetLeft i offsetTop

– previous() – poprzedni węzeł (rodzeństwo)

– previousSiblings() – jak wyżej, ale wszystkie poprzednie węzły

– readAttribute() – odczyt atrybutu, np.:

$('mylink').readAttribute('href'); // '/tags/prototype'

– recursivelyCollect(property) – rekursywne zbieranie elementów których stosunek do danego elementu jest określony przez właściwość (property), np.:

$('my-ul-li-element').recursivelyCollect('firstChild');

– relativize() – czyni element pozycjonowanym względnie

– remove() – usuwanie, np.:

// usuwa element z dokumentu (i ewentualnie zwraca go):
var x = $('divek').remove();

– removeClassName() – usuwa klasę CSS, np.:

$('divek').removeClassName('klasa');

– replace() – podmiana elementu, np.:
replace(element[, html]); // parametr html określa nową zawartość, która może zostać dodana

– scrollTo() – przewija do danego elementu, np.:

$(element).scrollTo();

– select() – wybiera element

– setOpacity() – manipulacja przeźroczystością

// 50% transparency - ustawia 50% przezroczystości 
$(element).setOpacity(0.5);

– setStyle() – dynamiczne ustawienie stylu, np.:

$(element).setStyle({
    backgroundColor: '#900',
    fontSize: '12px'
});

– show() – pokaż element (jeśli ukryty), patrz: hide()

– siblings() – tablica sąsiadów, np.: $(‚divek’).siblings();

– stopObserving() – przestań obserwować / obsługiwać zdarzenie; patrz: observe()

Przykład:

$(element).stopObserving('click', coolAction); 
// unregister coolAction

– toggle() – zmienia widoczność elementu, wywoła show() gdy ukryty, hide() gdy widoczny:

$('el').toggle();

– toggleClassName() – podobnie jw. – dodaje / usuwa klasę, jak mamy np. class=”foo bar”;

elem.toggleClassName("foo"); // class="bar";

– undoClipping() – odwrotna do makeClipping

– undoPositioned()– przywraca poprzednią pozycję dla elementu

– up() – zwraca pierwszego przodka elementu

– update() – aktualizacja zawartości elementu

– viewportOffset() – zwraca współrzędne x, y

– visible() – czy element jest widoczny

$('visible').visible(); // true lub false

– wrap() – dodaje wrapper do elementu / obudowuje go innym elementem), na przykład:

var div = new Element('div', { 'class': 'table-wrapper' });
$('elem').wrap(div);

Podsumowanie

Tym spisem metod kończymy część 2. kursu Prototype JS. Zapraszamy do podsumowującej części 3. Będzie to część ostatnia, ale tylko podstawowego kursu Prototype JS, nie artykułów związanych z tą biblioteką.

Samych ciekawych narzędzi i ułatwień, które zbudowano w oparciu o nią i są godne polecenia, jest całkiem sporo.

Dziękuję za uwagę.


Programista WWW i aplikacji mobilnych z wieloletnim doświadczeniem, początkujący bloger. Pasjonat programowania, nowych technologii, e-commerce, a także sportu i motoryzacji.

Twitter LinkedIn Google+ Skype Xing 

Podaj dalej: Share on Facebook0Tweet about this on TwitterShare on Google+1Share on LinkedIn0Share on Tumblr0Digg thisEmail this to someonePin on Pinterest1
Możesz skomentować leave a response, lub podać trackback z własnej strony.