Strona używa cookies (ciasteczek). Dowiedz się więcej o celu ich używania i zmianach ustawień. Korzystając ze strony wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki.    X

jQuery plugin - własna wtyczka od podstaw

W tym krótkim wpisie, przedstawię jak szybko można napisać własny plugin do jQuery. Z racji tego, iż jest to obecnie jeden z najbardziej popularnych frameworków JavaScriptowych, znajomość tworzenia rozszerzeń jest bardzo przydatna.

Nasz plugin

W celu uniknięcia tworzenia sztuki dla sztuki, stworzona wtyczka będzie coś robić. Jej zadaniem będzie zmiana tła w środku elementu, po kliknięciu na tym obiekcie. Jako parametry przyjmować będzie dwa kolory, które co kliknięcie będą się zmieniać.

Baza

Każdy plugin dla jQuery składa się z bazy, która zawsze jest identyczna dla każdej wtyczki, bez względu na to w jaki sposób będzie dalej tworzona.

Pierwszym krokiem jest dostarczenie naszemu pluginowi dostępu do $ oraz zapewnienie unikalności nazw i niekolidowania z innymi wtyczkami:

(function($) { //baza pod plugin })(jQuery

Teraz przyszedł moment aby dodać do kodu funkcję, w której nasz plugin będzie działał:

(function($) { $.fn.changeColor = function() { //ciało naszego pluginu } })(jQuery);

Na tym etapie nazywamy nasz plugin. W tym przypadku będzie to changeColor. Już w tym momencie nasz plugin istnieje, mimo, iż nic nie robi można go wywołać:

$("div").changeColor();

Łańcuchowość

Pluginy jQuery opierają się na zasadzie, iż każda wtyczka zwraca przetworzony/wybrany łańcuch obiektów dalej. Dzięki czemu można pisać ciąg poleceń np.:

$("div").attr("data-type","slider").addClass("slider");

W powyższym przykładzie, ze strony wybieramy wszystkie elementy div i ustawiamy im atrybut data-type na slider. Dzięki temu, iż attr zwraca łańcuch divów z dodanym atrybutem, możemy ponownie przetworzyć dane i np. dodać do każdego diva klasę slider.

Łańcuchowośc zapewnimy, dzięki temu, iż plugin zwracać będzie element this, czyli dane które otrzymał do przetworzenia:

(function($) { $.fn.changeColor = function() { return this.each(function() { //ciało naszego pluginu }); } })(jQuery);

Parametry wejściowe

Nasz plugin powinien przyjmować parametry wejściowe, zatem należy zapewnić taką możliwość:

(function($) { $.fn.changeColor = function(options) { //parametry wejściowe var settings = $.extend( { colorFirst : 'Red', colorSecond : 'Green' }, options); return this.each(function() { //ciało naszego pluginu }); } })(jQuery);

Dzięki temu szybkiemu zabiegowi, uzyskaliśmy kilka ważnych rzeczy. Nasz plugin uzyskał możliwość inicjalizacji z parametrami wejściowymi. colorFirst oraz colorSecond mają odpowiadające wartości domyślne, które mogę być zmienione na te które poda użytkownik.
Możliwe wywołania:

$("div").changeColor({ colorFirst : 'Blue', colorSecond : 'Black' }); //parametry domyślne $("div").changeColor(); //ustawienie tylko jednego parametru $("div").changeColor({ colorSecond : 'Yellow' });

Metody publiczne i prywatne

Kolejny krok to dodanie metod. Jeśli nasza wtyczka ma być prosta można spokojnie zacząć kodować w ciele głównej metody pluginu. Jednakże, jeśli kod ma być bardziej złożony i dodatkowo udostępniać na zewnątrz metody, warto jeszcze chwilę poczekać.

Poniższy schemat jest zalecany, w przypadku pluginów posiadających publiczne metody. Dzięki takiemu stworzeniu metod, nie marnujemy niepotrzebnie nazw w obrębie jQuery.

(function($) { $.fn.changeColor = function(options) { //metoda prywatna function onClick(event) { //ciało metody prywatnej } //metody publiczne var methods = { swapColors: function() { //wystawiona metoda }, destroy: function() { //destruktor } }; return this.each(function() { //ciało naszego pluginu if(methods[options]){ //wywołana metoda publiczna return methods[options].apply( this, arguments ); } else if (typeof options === 'object' || ! options ){ //wywołany konstruktor var settings = $.extend( { colorFirst : 'Red', colorSecond: 'Green' }, options); //inicjalizacja pluginu return; } else{ //bład $.error('changeColor: no method: '+ options); } }); } })(jQuery);

Powyżej stworzono obiekt methods, zawierający metody publiczne. SwapColors jest publiczną metodą wystawioną na zewnątrz. Taki zabieg powoduje, iż do metody odwołujemy się podobnie jak ma to miejsce w pluginie jQuery UI:

$("div").changeColor('swapColors');

Dodatkowo prywatna metoda onClick będzie użyta jedynie wewnątrz wtyczki.

Destruktory

Pisząc plugin do jQuery, warto zadbać o to by można było nasz plugin "odinstalować". Należy zatem dodać metodę która będzie sprzątała po naszej wtyczce. W takim destruktorze warto zadbać o to, by znalazło się w nim usunięcie np. eventów, które podczepiliśmy podczas inicjalizacji lub innych danych wrzuconych do htmla. Do powyższego kodu dołączono metodę destroy, wywołuje się ją podobnie jak inne publiczne metody.

Dodawanie funkcjonalności

Możemy zatem przystąpić do dodawani funkcjonalności do naszego pluginu.
Na początek dodamy inicjalizację wtyczki:

//inicjalizacja pluginu $this = $(this); data = $this.data("changeColor"); if(!data) { data = $this.data("changeColor", settings); $this.bind("click", onClick); } $this.css("background-color", settings.colorFirst); data.first = true;

Powyższy kod sprawdza, czy przypadkiem plugin dla danego elementu nie jest już jest dodany. W tym przypadku sprawdzić można, czy element posiada dane pod wybranym kluczem: changeColor. W prosty sposób unikamy podwójnego inicjalizowania tego samego elementu, a także jest to świetny sposób na przechowanie parametrów wejściowych. Do elementu, podczepiliśmy metodę onClick, która będzie wywoływana dla eventu odpowiadającego za kliknięcie myszką. Zmienna first będzie informować, o tym który kolor mamy ustawić jako tło.

Przyszła kolej na dodanie ciała dla funkcji onClick, która podmienia tło dla klikniętego elementu;

//ciało metody prywatnej $this = $(this); data = $this.data("changeColor"); data.first = !data.first; $this.css("background-color", data.first ? data.colorSecond : data.colorFirst); return true;

Dodajmy jeszcze kod dla publicznej metody SwapColors, która zamienia kolejnością tła:

//wystawiona metoda $this = $(this); data = $this.data("changeColor"); tmp = data.colorSecond; data.colorSecond = data.colorFirst; data.colorFirst = tmp;

Ostatni krok to uzupełnienie metody dla destruktora:

//destruktor $this = $(this); $this.unbind("click"); $this.css("background-color",""); $this.removeData("changeColor");

Gdy zechcemy usunąć plugin z elementu wywołujemy metodę destroy. Pozbywamy się eventa dla kliknięcia na element i czyścimy wszelkie dane.

Nasz gotowy plugin

(function($) { $.fn.changeColor = function(options) { //metoda prywatna function onClick(event) { //ciało metody prywatnej $this = $(this); data = $this.data("changeColor"); data.first = !data.first; $this.css("background-color", data.first ? data.colorSecond : data.colorFirst); return true; } //metody publiczne var methods = { swapColors: function() { //wystawiona metoda $this = $(this); data = $this.data("changeColor"); tmp = data.colorSecond; data.colorSecond = data.colorFirst; data.colorFirst = tmp; }, destroy: function() { //destruktor $this = $(this); $this.unbind("click"); $this.css("background-color",""); $this.removeData("changeColor"); } }; return this.each(function() { //ciało naszego pluginu if(methods[options]){ //wywołana metoda publiczna return methods[options].apply( this, arguments ); } else if (typeof options === 'object' || ! options ){ //wywołany konstruktor var settings = $.extend( { colorFirst : 'Red', colorSecond: 'Green' }, options); //inicjalizacja pluginu $this = $(this); data = $this.data("changeColor"); if(!data) { data = $this.data("changeColor", settings); $this.bind("click", onClick); } $this.css("background-color", settings.colorFirst); data.first = true; return; } else{ //bład $.error('changeColor: no method: '+ options); } }); } })(jQuery);

Jak widać tworzenie pluginów do jQuery nie jest trudne. A zatem, do dzieła! :)  

internet porady programowanie

Komentarze

0 nowych
gowain   19 #1 26.01.2012 22:00

Fajny wpis, jquery to potęga :) A nie zadziałało by coś takiego, króciutkiego, korzystającego już z gotowych rozwiązań w jQuery (moje rozumowanie może być błędne, tak to w sferze rozmyślań skleciłem przed chwilą :P)

$('#div').click(function()
{
$('body').css("background-color", "red");
});

spaczek   2 #2 26.01.2012 22:03

Śwetny wpis :) po zaliczeniach się zabiorę za zabawę z jQuery :)

senssei   2 #3 26.01.2012 22:12

Dobry wpis. jQurey zaczyna być swego rodzaju standardem jak sam JS.

djfoxer   18 #4 26.01.2012 23:06

@gowain
To co zapisałeś robi coś takiego:
1.dla dowolnego elementu html o id="div" podczepia event click
2. po kliknięciu na ten element zmieniane jest tło dla całej strony na czerwony
i już :)

Przykład w wpisie jest czysto "akademicki" i pokazuje jak tworzyć plugin. Mimo wszystko można dodać dowolny element i kolory tła zmieniają się co kliknięcie w wybranym elemencie :)

gowain   19 #5 26.01.2012 23:14

Znaczy się wiem co robi to co napisałem, ale tak patrzę na Twój plugin i wydaje się strasznie długi i pytanie czy da się go jakoś zoptymalizować, żeby korzystał w dużo większym stopniu z funkcji zapisanych już w jQuery? Z ciekawości pytam, rozumiejąc także, że to akademicki przykład, w którym wszystko powinno być łopatologicznie i bez tricków :P

djfoxer   18 #6 26.01.2012 23:33

@gowain
To zależy co chcesz zrobić :)
W kodzie jest sporo metod z jQ:
css: http://api.jquery.com/css
data: http://api.jquery.com/jQuery.data
removeData: http://api.jquery.com/jQuery.removeData

djfoxer   18 #10 26.01.2012 23:37

(Coś z dodawaniem komentarzy się dzieje jak w linku do extend zmienimy jQueryextend na jQuery.extend nie dodaje się! )

Wracając do pytania. Najbardziej prymitywny plugin do zmiany tła w wybranym elemencie na czerwony można zrobić tak:

(function($) {
$.fn.changeColor = function() {
return this.each(function() {
this.click(function(){ $(this).css("background-color", "red"); });
});
}
})(jQuery);

Mimo prostoty, już w tym momencie mamy łańcuchowość!

gowain   19 #11 26.01.2012 23:44

o właśnie, takie rozwiązanie lubię :P Wbrew pozorom, dla mnie ten przykład jest jaśniejszy :) Dzięki za garść informacji.

djfoxer   18 #12 27.01.2012 09:10

@gowain
Ale jakbyś szukał jak do pluginu jQuery dodać jeszcze:
- parametry wejściowe
- metody publiczne/prywatne
- destruktor/inicjalizator
- dane prywatne
to wiesz gdzie szukać;)

gowain   19 #13 27.01.2012 10:06

Ja głównie używam gotowych rozwiązań :P Czasami coś własnymi siłami modyfikuję, ale na szczęście do tej pory to wystarczało :) Ale dzięki - zawsze się przyda.

flaszer   10 #14 27.01.2012 15:51

Myślę, że czegoś takiego tutaj brakowało. W ogóle mało jest wpisów o JS, a co za tym idzie, jQuery. Chyba czas coś naskrobać ;)

djfoxer   18 #15 27.01.2012 16:27

@flaszer
Już ile można o tym ACTA klepać :P

skandyn   9 #16 27.01.2012 17:29

Dobre to i trzeba będzie przetestować ten Twój plugin. Co więcej to pewnie się komuś przyda takie coś na stronce WWW. Jeśli chodzi o mnie to mam coś podobnego w PHP-Fusion, czyli przyciski do zmieniana koloru tła.

Pozdrawiam.

  #17 16.04.2013 08:17

Jak w takich metodach publicznych obsłużyć parametry? Dla Twojego przykładu chciałbym żeby metoda swapColors przyjmowała hex koloru.

djfoxer   18 #18 16.04.2013 13:24

@Rozek
Można zrobić tak:

1.
$.fn.changeColor = function(options)
zamienić na:
$.fn.changeColor = function(options,par)

2.
return methods[options].apply( this, arguments );
zamienić na: return methods[options].apply( this, [par] );

3.
swapColors: function()
zamienić na: swapColors: function(prvOp)

4.
w środku swapColors:
data.colorSecond = prvOp.c1;
data.colorFirst = prvOp.c2;

wywoływanie może być wówczas takie:
$("div").changeColor('swapColors',{c1:"yellow",c2:"green"});

Autor edytował komentarz.
  #19 16.04.2013 16:43

Dzięki @djfoxer
To jeszcze do kompletu: jak zwracać wartości z metod? :-) Dla Twojego pluginu niech będzie, że chcemy metodę publiczną, która powie nam jaki aktualnie mamy kolor.

djfoxer   18 #20 16.04.2013 17:35

@Rozek
Wystarczy pomiędzy deklaracją
var methods
,a
return this.each(function() { //ciało naszego pluginu
wrzucić kod:

if(options == "getColors"){
v = new Array();
this.each(function(){
$this = $(this);
v.push({
item: $this,
color: $this.data("changeColor")
});
});
return v;
};

Odwołanie do metody:

$("div").changeColor("getColors")

zwróci listę par (obiekt, kolory), gdyż selektor może pobrać kilka obiektów mających rożne kolory.

  #21 05.03.2015 10:39

nie jestem programista tylko audytorem, dlatego pytanie do Biegłych: czy jest jakieś ryzyko w użyciu jQuery.extend(Drupal.settings
gdzie odniesienie się do domeny drupal.org daje wynik audytu strony w niezależnych testach jako strony potencjalnie niebezpiecznej o statusie "blacklist" i z zawartością malware?

  #22 01.06.2016 15:48

"    $.fn.changeColor = function() {
        return this.each(function() {
          //ciało naszego pluginu"