IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Ako na vlastné jQuery plug-in

jQuery je jedným z najobľúbenejších javascriptových frameworkov vôbec. Sprvu to bola len knižnica, ktorá mala poskytovať CSS selektory do jazyka JavaScript, ale potom čo Dean Edwards vydal svoju výbornú knižnicu cssQuery, sa vývoj jQuery posunul trošku iným smerom. Autorom knižnice jQuery je John Resig.

Dosť bolo teórie o jQuery, teraz pôjdeme programovať. Ako už napovedá titulok článku, napíšeme si vlastné plug-in do jQuery. Určite ste sa už s nejakým takýmto pluginom stretli. Volajú sa rovnako ako akákoľvek funkcia v tejto knižnici a to napríklad takto $(element).funkce().

Pluginov je na internete veľa, možno aj preto je framework tak úspešný. Môže sa ale stať, že vám žiadny tento plug-in nebude vyhovovať a to treba licencií. Tá totiž ani zďaleka nemusí byť iba open-source, a tak sa môžete stretnúť aj s platenými plug-iny. Avšak rovnako tak môžete platené pluginy vydávať sami. Tento článok je úvodom do tvorby vlastných doplnkov do jQuery. Článok je založený na vývoji reálneho plug-inu a to na jednoduchom slideru obsahu.

Štruktúra HTML & CSS

Keď píšeme vlastné doplnok, musíme si uvedomiť, aká bude štruktúra HTML a podľa nej sa zariadiť a nastylovať ju. Chceme slider obsahu, a preto pre nás bude najlepšie použiť zoznam, teda element <ul>. Nastylujeme ho podľa tried, ktoré priradí sám plug-in. Tu je malá ukážka HTML štruktúry so základnými CSS štýly:

Html štruktúra

<ul>
    <li>Obsah prvního slidu</li>
    <li>Obsah druhého slidu</li>
</ul>

CSS štýly

/**
 * Vsechny slidy
 */
ul.easySlider-content {
    padding: 20px;
    margin-bottom: 25px;
    position: relative;
    height: 250px;
    z-index: 100;
    -webkit-box-shadow: 0 0 10px #aaa;
    -moz-box-shadow: 0 0 10px #aaa;
    box-shadow: 0 0 10px #aaa;
    border: 1px solid #dcdcdc;
    background: #ffffff;
    background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIwJSIgeTI9IjEwMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIxJSIgc3RvcC1jb2xvcj0iI2ZmZmZmZiIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiNlZWVlZWUiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+);
    background: -moz-linear-gradient(top,  #ffffff 1%, #eeeeee 100%);
    background: -webkit-gradient(linear, left top, left bottom, color-stop(1%,#ffffff), color-stop(100%,#eeeeee));
    background: -webkit-linear-gradient(top,  #ffffff 1%,#eeeeee 100%);
    background: -o-linear-gradient(top,  #ffffff 1%,#eeeeee 100%);
    background: -ms-linear-gradient(top,  #ffffff 1%,#eeeeee 100%);
    background: linear-gradient(top,  #ffffff 1%,#eeeeee 100%);
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee',GradientType=0 );
}

ul.easySlider-content li {
    margin-right: 20px;
}

/**
 * Aktivní slide
 */
ul li.active {
    display: block !important;
}

/**
 * Posuvne sipky
 */
a.arrowLeft {
    display: block;
    width: 70px;
    height: 70px;
    background: #fff url('images/arrow_left.png') 3px center no-repeat;
    position: absolute;
    margin: 140px -48px;
    border-radius: 50px;
    border: 5px solid #dcdcdc;
}

a.arrowRight {
    display: block;
    width: 70px;
    height: 70px;
    background: #fff url('images/arrow_right.png') 18px center no-repeat;
    position: absolute;
    margin: 140px 770px;
    border: 5px solid #dcdcdc;
    border-radius: 50px;
}

a.arrowLeft:hover, a.arrowRight:hover {
    background-color: #dcdcdc;
}

JQuery.fn

jQuery.fn je, dalo by sa povedať, menný priestor pre vaše doplnky. Všetky funkcie umiestnené práve do tohto objektu môžeme zavolať priamo z jQuery. Kontextom týchto funkcií je práve vybraný element. Čo je to ale ten kontext funkcií? Každá funkcia v JavaScripte je spracovávaná v nejakom kontexte. Laicky povedané je to to kľúčové slovo this. Ak teda vložíme funkciu do jQuery.fn a zavoláme náš plug-in napr .: $('#obsah').nazevMeFunkce(), bude v danej funkcii kľúčové slovo this obsahovať element s id="obsah". Bude však prístupný ako objekt HTMLElement, nie ako jQuery objekt. Ak by sme ho chceli použiť ako objekt jQuery, jednoducho uvedieme this ako parameter jQuery objektu: jQuery(this) alebo $(this) (toto sú totožné zápisy).

Keď už vieme, kam vložiť náš plug-in, môžeme začať písať. Všeobecne je najlepšie náš doplnok zabaliť do anonymný funkcie, aby sa nepřepisovaly premenné a tak ďalej. Je to lepšie aj preto, že znak $ používajú aj iné knižnice (okrem jQuery) ako zástupný znak a to v anonymných funkciách riešiť nemusíme. Mali by sme si tiež navrhnúť, ako budeme volať ďalšie funkcie v plug-inu a ako vyriešime užívateľské nastavenie. Uvediem teraz jednoduchý príklad základného plug-inu s logikou volanie funkcií, ktorý potom rozoberiem.

// Naše anonymní funkce - jediným parametrem je $, který zastupuje objekt jQuery
(function( $ ) {

    // Zde budou metody, které může z plug-inu zavolat i sám uživatel
    var methods = {

        // Inicializační metoda - je volána z hlavní funkce
        init: function( o ) {}
    };

    // Vstupní funkce plug-inu
    $.fn.easySlider = function( method ) {
        // Pokud máme jméno funkce, kterou chceme zavolat
        if ( methods[method] ) {
            // Zavoláme danou funkci se všemi ostatními předanými argumenty plug-inu
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if ( typeof method == 'object' || !method ) {
            // Pokud ne, zavoláme inicializační metodu
            return methods.init.apply(this, arguments);
        } else {
            // Pokud metoda neexistuje, vypíšeme chybu
            $.error('Metoda ' + method + ' neexistuje v plug-inu jQuery.easySlider');
        }
    };

    // Základní nastavení
    $.fn.easySlider.defaults = {
    };
})( jQuery ); // zavoláme funkce s parametrem jQuery

Vytvorili sme si funkciu easySlider() v objekte jQuery.fn. Môžeme ju teda zavolať napr .: $('ul#slider').easySlider().

Ale čo keď bude potrebné niečo nastaviť alebo zavolať nejakú vnútornú funkciu pluginu? Je veľmi nepraktické meniť samotný kód pluginu. Tieto kódy sú tiež často minimalizované a tak to ani nejde. Vyššie uvedený príklad však počíta aj s týmto. Ako argument môžeme uviesť buď objekt, v ktorom bude všetko nastavenie plug-inu, alebo meno funkcie v objekte methods a alebo tiež nič a plugin si potom sám zavolá methods.init(). Toto je len jeden spôsob, ako urobiť logiku volanie funkcií. Dalo by sa to urobiť aj inak. Pre nás je však toto veľmi praktické, a tak nemusíme nič riešiť.

Naposledy tu máme objekt defaults. V ňom je uložené základné nastavenie. Je to preto, aby užívateľ nemusel nastavovať všetko, ale len to, čo práve chce inak.

Ešte než sa vrhneme na samotný plug-in, chcel by som ujasniť, čo vlastne robí funkcie apply(). Každá funkcia v JavaScripte má nejaký svoj kontext, v ktorom sa spracováva, ako už som spomenul vyššie. Funkcia apply() zavolá danú funkciu s kontextom, aký si zvolíme. Má celkom dva argumenty, prvým je práve ten kontext. Ten sme si nastavili na this, teda na práve vybraný element. Druhým argumentom je pole, v ktorom uvedieme všetky argumenty funkcie. Tu uvádzame premennú arguments, čo je pole všetkých argumentov funkcie.

Inicializačnú metóda

Máme základ a tak si každý prvok inicializujeme. Jediný argument bude objekt s užívateľským nastavením. Aby sme však mali istotu, že sú v tomto objekte všetky nastavenia, rozšírime defaults práve o tento objekt. Opäť uvediem celý kód funkcie, ktorý vzápätí rozoberiem:

// Inicializační metoda - je volána z hlavní funkce
init: function( o ) {
    // Získáme nastavené volby plug-inu
    o = $.extend({}, $.fn.easySlider.defaults, o);
    // Uložíme si aktuální kontext funkce (element plug-inu)
    var $that = $(this);

    // Funkce po kliknutí na šipky
    var left_click = function( e ) {
        e = $.event.fix(e);
        e.preventDefault();
        $that.easySlider("prev");
    }, right_click = function( e ) {
        e = $.event.fix(e);
        e.preventDefault();
        $that.easySlider("next");
    };

    // Projdeme všechny předané elementy a inicializujeme pro ně plug-in
    return this.each(function() {
        // Najdeme všechny obrázky ve slideru
        var $items = $(this).find('li'),
            count = $items.length,
            $self = $(this);

        // Všechny je skryjeme a pozicujeme absolutně
        $items.css({ display: 'none', position: 'absolute' });

        // Vložíme seznamu třídu pro přístupnější manipulování v CSS
        $self.addClass('easySlider-content').data('speed', o.speed);

        // Aktivujeme první element
        $($items.get(o.active)).addClass("active");

        // Vytvoříme si postranní šipky pro posun slideru
        var $arrowLeft = $('&lt;a /&gt;').attr('href', '#left').addClass('arrowLeft');
        var $arrowRight = $('&lt;a /&gt;').attr('href', '#right').addClass('arrowRight');
        // Nastavíme callback na kliknutí
        $arrowLeft.bind('click', left_click);
        $arrowRight.bind('click', right_click);
        // Vložíme šipky před seznam slidů
        $self.before( $arrowRight );
        $self.before( $arrowLeft );
    });
}

Hneď na prvom riadku je použitá funkcia jQuery.extend(). Táto funkcia rozširuje ľubovoľný počet objektov, kde objekty uvedené poslednýkrát majú väčšiu prioritu. Prvý argument je cielený objekt, kam chceme výsledok uložiť (viac info v oficiálnej dokumentácii jQuery.extend). A teraz česky. Vezmeme premenné a funkcie z objektu defaults a ak existuje rovnomenná funkcie či premenná v objekte o, prepíšeme jej hodnotu na hodnotu, ktorá je v objekte o. To zaistí, že nemusíme zložito zisťovať, či ak nám užívateľ zadal všetky voľby. Ďalšie je pomocná premenná $that. Okrem jednoduchšieho zápisu, ktorý nám možno ušetrí desatinu sekundy, sú vo funkcii methods.init() definované ešte iné funkcie s iným kontextom a v týchto funkciách by výraz $(this) znamenal úplne niečo iné. Preto si ho musíme uložiť do premennej, ktorá bude prístupná aj z týchto funkcií.

Celá funkcia vracia this, teda opäť vybrané elementy, a pre každý tento element vykoná nastavenia plug-inu. Poďme si teda kód podrobne rozobrať. Keďže predpokladáme, že štruktúra slideru bude zoznam (v HTML <ul> a <li>), nájdeme si všetky elementy <li> a uložíme si ich do premennej $items. Ďalej tu máme pomocnú premennú, v ktorej je počet elementov <li> (teda počet slidov) a opäť pomocnú premennú $self, v ktorej je kontext funkcie, v ktorej pracujeme. Ten sa totiž zmenil s použitím jQuery.each, ako ste si mohli všimnúť.

Všetko sme si už načítali do premenných, a tak si ich nastavíme. Zo všetkého najskôr skryjeme všetok obsah a nastavíme mu absolútnu pozíciu. To z toho dôvodu, aby sa nám obsah nerozhádzal pri prechode. Ďalej potom elementu <ul> pridáme triedu .easySlider-content a nastavíme ju data-speed na hodnotu, ktorú zadá používateľ. To urobíme preto, aby sme si ju mohli v inej funkcii prečítať, ale nebudem predbiehať.

Teraz už vytvoríme tlačidlá pre prechod na ďalšiu alebo predchádzajúcu slide. Nastavíme im danú triedu a vložíme ich pred slider. Preskočil som zámerne bind('click'). Musíme totiž povedať skriptu, čo sa má stať po kliknutí na tieto šípky. Použijeme vopred nadefinované funkcie left_click() a right_click(). Tieto funkcie máme nadefinované ešte pred return, aby sme ich nemuseli definovať napríklad aj sto krát, čo by mohlo spomaliť celý skript. V tejto funkcii by ste totiž mali definovať len to najnutnejšie, čo sa musí takto vykonať naozaj pre každý element. Čo by som chcel zdôrazniť v týchto funkciách je použitie $.event.fix(e). Ako už možno viete, v niektorých prehliadačoch musíte pristupovať k premennej udalosti (event) inak alebo sú tam inak nazvané parametre, takže si musíme dávať pozor. Čo už však málokto vie je, že táto jQuery funkcia to zariadi za nás a my už sa s tým nemusíme znepokojovať. Potom len použijeme e.preventDefault(), ktorá zamedzí prevedenie východiskovej udalosti (u odkazov je to presmerovanie na danú adresu href). Na konci funkcia je zavolaná metóda methods.next() cez našu volací logiku. Synonymom pre toto volanie je methods.next.apply(that);, Kde that je kontext funkcie init().

Verejné a privátne funkcie

Ako som už hovoril, všetky funkcie v objekte methods sú volatelné z nášho pluginu a to týmto spôsobom: $(element).easySlider("nazev_funkce", ["první parametr", "druhý parametr", ...]); (Hranaté zátvorky naznačujú len to, že sú tieto argumenty nepovinné - v normálnom skriptu tam nie sú!). Funkcie sú teda verejné. Môžeme tiež vytvoriť privátne funkcie a to tak, že ich uložíme mimo objekt methods, do tej istej anonymný funkcie. Takéto funkcie by boli prístupné len v našej anonymný funkciu a zvonku by prístupné neboli. V tomto prípade privátne metódy nepoužívame, ale niekedy sú veľmi užitočné.

Teraz už zostávajú len tri funkcie. Jedna nastaví aktívnu vrstvu a zároveň vykoná animáciu (tzv. Slide) na základe odovzdaného indexu. Nazveme jej napríklad active(). Ďalšie dve budú funkcie prev() a next(), ktoré vypočítajú index predchádzajúceho, resp. ďalšieho slidu a odovzdajú ho funkciu active().

// Funkce nastaví aktivní slide (Index od 0 do počtu obrázků v galerii)
active: function( index, direction ) {
    // Nastavíme rychlost
    speed = $(this).data('speed') || 800;
    // Nastavíme směry efektů
    directionHide = direction || 'left';
    directionShow = directionHide == 'left' ? 'right' : 'left';
    // Skryjeme aktivní položku
    $(this).find('li.active').hide('slide', { direction: directionHide }, speed);
    // Všem položkám odstraníme třídu .active
    $(this).find('li').removeClass('active');
    // Načteme aktivní slide
    var slide = $(this).find('li').get(index) || false;
    // Zobrazíme ho
    $(slide).addClass('active').show('slide', { direction: directionShow }, speed);
    // Vrátíme aktivní element
    return $(this).find('li').get(index) || false;
},

// Přesune se na další slide
next: function() {
    // Najdeme další element a zjistíme jeho index, ke kterému přičteme +1
    var index = ($(this).find('li.active').index()+1);
    // Aktivujeme tento slide, pokud existuje. Pokud ne, automaticky se přesuneme na první (nultý)
    return $(this).easySlider("active", ($(this).find('li').get(index) ? index : 0));
},

// Přesune se na předchozí slide
prev: function() {
    var index = $(this).find('li.active').index()-1 < 0 ?$(this).find('li').length-1 : $(this).find('li.active').index()-1;
    // Aktivujeme slide s títo indexem
    return $(this).easySlider("active", index, 'right');
},
/** Metoda init ... */

$ (element) .easySlider ( "active", index, direction)

Stačí rozobrať tieto tri metódy a náš plugin bude hotový. Prvá funkcia active() aktivuje element, ktorý zistíme z odovzdaného indexu (viď. Prvý parameter funkcie). Druhý parameter direction je nepovinný (buď 'left' alebo 'right') a ten určuje smer, kam sa slider posunie. Funkcia na zobrazenie a skrytie elementu používa jquery.effects.core.js z knižnice jQuery UI. Preto je tento plug-in na nej závislý. Ak budete chcieť použiť len čisto jQuery, môžete ich nahradiť funkciami fadeIn() a fadeOut() alebo slideDown() a slideUp() alebo jednoducho animate(), to už je na vás.

$ (element) .easySlider ( "next")

Posunie slider na ďalší element. Ak ďalšie nie je, presunie sa na začiatok. Volá funkciu active(). Funkcia prev() je rovnaká s tým rozdielom, že sa presunie na predchádzajúcu alebo posledný element.

Pár tipov nakoniec

  • Minimalizujte svoj kód, ale poskytujte verzia aj normálny (pokiaľ teda nechcete robiť komerčné pluginy). Tak budú môcť vaše pluginy ďalej vyvíjať a upravovať aj iní, pokiaľ to nebude v rozpore s vami danou licenciou. Pre minimalizovanie kódu odporúčam skript Deana Edwardsa - Packer
  • Do používateľského nastavenia vložte čo najviac vecí. Spíšte potom podrobnú dokumentáciu tohto nastavenia.
  • Snažte sa moc nenastavovať CSS štýly. To nechajte na externých súboroch. V skripte nechajte len nevyhnutné štýly.
  • Píšte nevtieravý kód. Nechcite po užívateľoch, aby museli pridávať HTML, to predsa dokáže JavaScript taky ;)
  • Pred vydaním otestujte svoj výtvor v čo možno najviac prehliadačoch. Ak ho nejaký prehliadač nepodporuje, napíšte to do dokumentácie.

 

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 1360x (90.17 kB)
Aplikácia je vrátane zdrojových kódov v jazyku JavaScript

 

Predchádzajúci článok
Štýlovanie v jQuery
Všetky články v sekcii
Základy jQuery
Článok pre vás napísal Drahomír Hanák
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor v současné době studuje Informatiku. Zajímá se o programování, matematiku a grafiku.
Aktivity