devblog, portfolio

movie producer, zend framework, php, jquery pluginy



Jak stworzyć plugin do jQuery?

Wiele razy pisałem już o bibliotece dla JavaScript'u o nazwie jQuery. Każdy kto choć raz z tej biblioteki korzystał na pewno zgodzi się ze mną, jeśli powiem, że to bardzo dobrze pomyślane i wykonane narzędzie z mnóstwem dodatków.

Jak korzystać z dobrodziejstw tego narzędzia pisałem już wielokrotnie. Dzisiaj pokażę jak stworzyć własny dodatek.

Na początek trochę teorii

Zasada numer 1. Aby nasz dodatek był wygodny w użyciu dla osoby z niego korzystającej, musi implementować interfejs fluent. Jeśli nie wiesz co to takiego ten interfejs fluent, to powiem Ci Czytelniku, że na pewno już kiedyś się z nim spotkałeś, tylko po prostu nie wiesz, że tak się nazywał. Obiekt, który implementuje interfejs fluent. Tak samo jak i w PHP nie oznacza to, że musimy w jakiś specjalny sposób definiować obiektu. Wystarczy, że każda z jego metod (funkcji składowych) będzie zwracała this, czyli ten obiekt, na którym jest ona wykonywana.

Dzięki temu metody na obiekcie jQuery można wykonywać "w łańcuchu" np.:

$(document).ready(function() {
     $('div')
         .css('border','1px solid #000')
         .text('Text!!!')
         .show();
});

Zasada numer 2. Dodatek tak jak powiedziałem, implementuje interfejs fluent. Czy to znaczy, że jest obiektem? Niezupełnie. Przy projektowaniu języka JavaScript popełniono trochę błędów (niektóre opisał Karol "Xion" Kuczmarski). Jednym z nich jest bardzo upośledzona obiektowość. Jedynym odpowiednikiem klasy w innych językach programowania jest tu... funkcja. ($, czyli inaczej jQuery jest nie klasę tylko obiektem - czyli funkcją!). Tak naprawdę większość dodatków będzie składała się z jednej funkcji, dlatego nie będziemy musili tworzyć osobnego obiektu. Jednak te bardziej skomplikowane będą mogły być obiektami, składającymi się z funkcji.

Skoro ustaliliśmy, że caly dodatek będzie składał się z funkcji będącej składową jakiegoś obiektu, to powiedzmy sobie, co to za obiekt. Będzie to obiekt fn, który należy do funkcji (obiektu) jQuery. Zatem deklaracją naszego dodatku będzie:

jQuery.fn.nazwa_dodatku = function(parametry) {
    // kod
};

Zapytacie pewnie, dlaczego nie użyjemy znaku dolara, zamiast nazwy jQuery, skoro są one równoznacznymi nazwami jednej funkcji. Znak dolara ($) jest często wykorzystywany w różnych bibliotekach JavaScriptu jako nazwa funkcji. Wtedy jQuery "popada w konflikt" z tą funkcją. Do typowych zastosowań mamy metodę jQuery.noConflict, która "uwalnia" znak dolara (nie jest on maską dla funkcji jQuery, więc nie możemy z niego korzystać). Tworząc dodatek zabezpieczamy się przed przypadkiem, w którym twórca skryptu, korzystając z naszego dodatku skorzysta z metody noConflict - używamy po prostu pewnej nazwy funkcji.

Pierwszy plugin

Na początek, żeby nie rzucać się od razu na głęboką wodę, zrobimy funkcję powiększającą rozmiar elementu (elementów) na którym została wykonana.

Najpierw deklarujemy zmienną o nazwie powieksz w obiekcie jQuery.fn.

jQuery.fn.powieksz = function() { }

Teraz, musimy dodać pomiędzy nawiasy klamrowe kod. Wywołamy tam funkcję składową jQuery.css na obiekcie this, który musimy najpierw przekazać do funkcji jQuery (żeby został z niego stworzony obiekt, na którym można spokojnie wywoływać funkcje składowe jQuery). Będzie to wyglądało tak jak na listingu nr 1.

No dobra. Ale ta funkcja jest jakaś niekompletna. Jeżeli naszej funkcji jQuery.powieksz użyjemy na zbiorze elementów, to zmodyfikowany zostanie tylko pierwszy z nich. Co prawda funkcja jQuery.css zostanie wywołana na wszystkich elementach zbioru, ale za to parametry w obiekcie size będą pochodziły od pierwszego elementu. W przypadku różnych rozmiarów kolejnych elementów większe z nich mogą zostać nawet pomniejszone - tego byśmy nie chcieli. Rozwiązanie problemu jest w funkcji przedstawionej na listingu nr 2.

Na zbiorze wykonujemy funkcję jQuery.each. Jej parametrem jest funkcja, która jest wykonywana na każdym elemencie zbioru. Tak więć this w tej funkcji odnosi się nie do zboiru, ale do obiektu przekazanego do niej, czyli pojedynczego elementu ze zbioru.

Działanie funkcji zaprezentowałem na demie nr 1.

Parametry

Wszystko działa. Możemy klikać i za każdym razem elementy zostaną powiększone o tę samą liczbę pikseli, ale co z tego? Takie coś możne napisać każdy i nie potrzebuje do tego naszego pluginu. Gdybyśmy dali możliwość przekazania do funkcji parametrów, sytuacja diametralnie by się zmieniła. Jeżeli można dokładniej powiedzieć dodatkowi jak ma działać, to jest on do czegoś przydatny.

Najlepszym sposobem na przekazanie parametrów, będzie zawarcie ich w obiekcie literalnym (czyli obiekcie ;), a następnie przekazanie go do funkcji, która brakujące prametry uzupełni domyślnymi.

Stwórzmy więc dodatek, który będzie dodawał do elementu zegarek - z datą lub bez. Funkcja będzie przyjmowała obiekt, z którego będzie wczytywała trzy parametry. Pierwszym z nich będzie prefix znaczników czasu, drugim format zegara, a trzecim typ boolean informujący o tym, czy do jednocyfrowych wartości mają być dodane na początku zera (np. dla wartości false: 10/2/2012, dla wartości true: 10/02/2012).

W naszym dodatku skorzystamy z obiektów: Date i String, a także wbudowanej funkcji setInterval. Aby uzupełnić brakujące wartości z obieku przekazanego przez użytkownika, skorzystamy z metody jQuery.extend.

Tworzymy funkcję

Na samym początku definiujemy funkcję, która będzie naszym pluginem. Wygląda to tak:

jQuery.fn.clock = function(param) {
    // kod
};

Teraz, wewnątrz tej funkcji tworzymy obiekt z domyślnymi parametrami. Będzie to wyglądało tak:

jQuery.fn.clock = function(param) {
    var defaults = {
        sign: '*',
        format: '*M/*D/*Y *H/*M/*S',
        addZero: true
    }
    var options = $.extend({},defaults,param);
};

Teraz, kiedy mamy już obiekt z parametrami, możemy zabrać się za tworzenie ciągu daty. Najpierw musimy stworzyć nowy obiekt String, który będzie zawierał ciąg options.format. Następnie za pomocą metody String.replace będziemy zamieniać kolejne znaczniki czasu na odpowiednie wartości. Musimy także pamiętać o tym, żeby sprawdzić parametr options.addZero i długość danego Stringu (właściwość String.length) (miesiąca, dnia, godziny, minuty, sekundy).

Nie będę tutaj po kolei opisywał każdej z tych czynności. Wszystko jest na listingu nr 3.

W ten sposób stworzyłeś Czytelniku swój dodatek do jQuery. Warto poeksperymentować ze stylami, bo efekt może być imponujący. Przypomnę, że w formacie możemy umieścić także tagi HTML. Daje nam to kolejne możliwości manipulowania konkretnymi elmentami daty i czasu. Ja pobawiłem się chwilkę i wyszło coś takiego (demo nr 2) :)

Kshyhoo Mozilla/5.0 (Windows NT 6.0; rv:10.0.1) Gecko/20100101 Firefox/10.0.1

Link do demo2 to link do demo1.

Kacper Kołodziej www Mozilla/5.0 (Windows NT 5.1; rv:10.0.1) Gecko/20100101 Firefox/10.0.1

Rzeczywiście. To przez pośpiech. Już poprawione

obi www Mozilla/5.0 (X11; Linux x86_64; rv:7.0.1) Gecko/20100101 Firefox/7.0.1

Dzięki. Bardzo ciekawy i pomocny artykuł.

Dodaj komentarz »