Con così tante persone che sviluppano i plugin jQuery, non è raro imbattersi in uno che semplicemente - per mancanza di parole migliori - fa schifo. Non ci sono esempi o documentazione, il plugin non segue le migliori pratiche, ecc. Ma tu sei uno dei più fortunati: questo articolo spiegherà in dettaglio le insidie che devi evitare.
jQuery non è estraneo a quelli di voi frequenti Nettuts +. I fantastici 30 giorni di Learn di Jeffrey Way su jQuery (e varie altre esercitazioni qui e altrove) ci hanno guidati lungo il percorso verso la fantastica saga di Sizzle. In tutto il clamore (e un sacco di balzi nell'adozione di JavaScript da parte di sviluppatori e venditori di browser), un sacco di plugin sono arrivati sulla scena. Questo è parzialmente il motivo per cui jQuery è diventata la libreria JavaScript più popolare disponibile! L'unico problema è che molti di loro non sono troppo grandi.
In questo articolo, ci concentreremo meno sul JavaScript in particolare, e molto altro sulle best practice per la distribuzione dei plugin.
Ci sono alcuni modelli che sono, più o meno, universalmente accettati come "The Right Way" per creare plugin jQuery. Se non stai seguendo queste convenzioni, il tuo plugin potrebbe ... succhiare! Considera uno dei modelli più comuni:
(function ($, window, undefined) $ .fn.myPlugin = function (opts) var defaults = // impostazione dei valori predefiniti per le opzioni // estendere le opzioni dai valori predefiniti con le opzioni dell'utente var options = $ .extend (default, opts || ); return this.each (function () // jQuery chainability // do plugin stuff);) (jQuery, window);
In primo luogo, stiamo creando una funzione anonima autoinvitante per proteggerci dall'uso di variabili globali. Passiamo dentro $
, finestra
, e non definito
. Gli argomenti con cui si chiama la funzione auto-invocazione sono jQuery
e finestra
; non viene passato nulla per undefined, così che se decidiamo di usare la parola chiave non definita all'interno del plugin, "undefined" sarà effettivamente indefinito.
Questo protegge da altri script potenzialmente a cui attribuire un valore dannoso
non definito
, ad esempiovero
!
$
è passato come jQuery; lo facciamo in questo modo per garantire che, al di fuori della funzione anonima, $
può ancora riferirsi a qualcos'altro interamente, come Prototype.
Passando la variabile per l'accesso globale finestra
l'oggetto consente un codice più compresso attraverso i processi di minification (cosa che dovresti fare anche tu).
Successivamente, stiamo usando il modello di plugin jQuery, $ .fn.PluginName
. Questo è un modo di registrare il tuo plugin da utilizzare con $ (Selector) .method ()
formato. Estende semplicemente il prototipo di jQuery con il tuo nuovo metodo. Se invece vuoi creare un plugin che definisce una funzione sull'oggetto jQuery, aggiungilo direttamente, in questo modo:
$ .PluginName = function (options) // estendere le opzioni, fare plugin
Questo tipo di plugin non è concatenabile, in quanto le funzioni definite come proprietà dell'oggetto jQuery in genere non restituiscono l'oggetto jQuery. Ad esempio, considera il seguente codice:
$ .splitInHalf = function (stringToSplit) var length = stringToSplit.length; var stringArray = stringToSplit.split (stringToSplit [Math.floor (length / 2)]); return stringArray;
Qui, stiamo restituendo una serie di stringhe. Ha senso restituirlo semplicemente come array, poiché è probabile che gli utenti vorranno usarlo (e possono facilmente inserirlo nell'oggetto jQuery se lo desiderano). Al contrario, considera il seguente esempio forzato:
$ .getOddEls = function (jQcollection) // return jQcollection.filter (function (index) var i = index + 1; return (index% 2! = 0););
In questo caso, probabilmente l'utente si aspetta che l'oggetto jQuery restituisca $ .getOddEls
; così, restituiamo il metodo filter, che restituisce la collezione jQuery definita dalla funzione che viene passata. Una buona regola è quella di avvolgere gli elementi restituiti nella funzione jQuery, specialmente se possono essere concatenati; se stai restituendo array, stringhe, numeri, funzioni o altri tipi di dati, lasciali scartati.
Probabilmente, la cosa più importante che puoi fare quando pubblichi il tuo codice è aggiungere la documentazione necessaria. Il divario tra ciò che spieghi agli sviluppatori e ciò che il codice effettivamente fa o può fare è il tempo che gli utenti non vogliono sprecare per capire i dettagli del tuo codice.
La documentazione è una pratica che non ha regole difficili; tuttavia, è generalmente accettato che più la documentazione è ben organizzata, meglio è.
Questo processo dovrebbe essere sia una pratica interna (all'interno / intersposta in tutto il codice) sia una pratica esterna (spiegando accuratamente ogni metodo pubblico, opzione e casi d'uso multipli in un wiki o readme).
I plug-in più popolari offrono accesso completo alle variabili (ciò a cui la maggior parte dei plugin si riferisce come oggetti "opzioni") che un utente potrebbe voler controllare. Possono anche offrire diverse configurazioni del plug-in in modo che sia riutilizzabile in molti contesti diversi. Ad esempio, consideriamo un semplice plug-in di slider. Le opzioni che l'utente potrebbe voler controllare includono la velocità, il tipo e il ritardo dell'animazione.
È buona pratica anche dare all'utente l'accesso a nomi di classi / ID che vengono aggiunti agli elementi DOM inseriti o manipolati dal plugin. Ma al di là di questo, possono anche voler accedere a una funzione di callback ogni volta che le transizioni della diapositiva, o forse quando la diapositiva torna all'inizio (un "ciclo" completo).
È compito tuo pensare a tutti i possibili usi e necessità del plugin.
Consideriamo un altro esempio: un plug-in che effettua una chiamata a un'API dovrebbe fornire l'accesso all'oggetto restituito dell'API. Prendi il seguente esempio di un semplice concetto di plugin:.
$ .fn.getFlickr = function (opts) return this.each (function () // jQuery chainability var defaults = // impostazione delle opzioni predefinite cb: function (data) , flickrUrl: // un valore predefinito per una chiamata API // estendere le opzioni dai valori predefiniti con le opzioni utente var options = $ .extend (default, opts || ); // chiama la funzione async e quindi chiama il callback // che passa nell'oggetto api che è stato restituito $ .ajax (flickrUrl, function (dataReturned) options.cb.call (this, dataReturned);););
Questo ci permette di fare qualcosa sulla falsariga di:
$ (selettore) .getFlickr (funzione (fdata) // dati di flickr si trova nell'oggetto fdata);
Un altro modo per pubblicizzare questo è offrire "ganci" come opzioni. A partire da jQuery 1.7.1 e versioni successive, possiamo usare .on (eventName, function () )
dopo la nostra chiamata al plugin per separare i comportamenti nelle proprie funzioni. Ad esempio, con il plugin sopra, potremmo cambiare il codice in modo che assomigli a questo:
$ .fn.getFlickr = function (opts) return this.each (function (i, el) var $ this = el; var defaults = // impostazione delle opzioni predefinite flickrUrl: "http://someurl.com" // qualche valore predefinito per una chiamata API var options = $ .extend (default, opts || ); // chiama la funzione async e quindi chiama il callback // che passa nell'oggetto api che è stato restituito $ .ajax (flickrUrl, function (dataReturned) // fa roba $ this.trigger ("callback", dataReturned);). error (function () $ this.trigger ("error", dataReturned);); );
Questo ci permette di chiamare il getFlickr
plug-in e catena altri gestori di comportamento.
$ (selettore) .getFlickr (opts) .on ("callback", function (data) // do stuff). on ("error", function () // gestisce un errore);
Potete vedere che offrire questo tipo di flessibilità è assolutamente importante; più complesse sono le azioni dei tuoi plugin, più complesso è il controllo che dovrebbe essere disponibile.
Ok, quindi il suggerimento numero tre ha suggerito che le azioni più complesse dei tuoi plug-in, il controllo più complesso che dovrebbe essere a disposizione. Un grosso errore, tuttavia, sta rendendo necessarie troppe opzioni per la funzionalità dei plugin. Ad esempio, è ideale per i plugin basati su UI avere un comportamento predefinito senza argomenti.
$ (Selector) .myPlugin ();
Certo, a volte questo non è realistico (come gli utenti possono recuperare un feed specifico, ad esempio). In questo caso, dovresti fare un po 'di sollievo per loro. Avere più modi di passare le opzioni al plugin. Ad esempio, supponiamo di avere un semplice plug-in fetcher per Tweet. Dovrebbe esserci un comportamento predefinito di quel fetcher con una singola opzione richiesta (il nome utente da cui si desidera effettuare il recupero).
$ (selettore) .fetchTweets ( "jcutrell");
L'impostazione predefinita può, ad esempio, prendere un singolo tweet, racchiuderlo in un tag di paragrafo e riempire l'elemento di selezione con quell'html. Questo è il tipo di comportamento che molti sviluppatori si aspettano e apprezzano. Le opzioni granulari dovrebbero essere proprio questo: opzioni.
È inevitabile, a seconda del tipo di plug-in, ovviamente, che dovrai includere un file CSS se è basato su manipolazioni dell'interfaccia utente. Questa è una soluzione accettabile al problema, in generale; la maggior parte dei plugin viene fornita in bundle con immagini e CSS. Ma non dimenticare la punta numero due: la documentazione dovrebbe anche includere come usare / fare riferimento ai fogli di stile e alle immagini. Gli sviluppatori non vorranno perdere tempo a cercare nel codice sorgente per capire queste cose.
Le cose dovrebbero solo ... funzionare.
Detto questo, è sicuramente una buona pratica utilizzare gli stili iniettati (che sono altamente accessibili tramite le opzioni del plugin) o lo stile basato su classe / ID. Questi ID e classi dovrebbero anche essere accessibili, tramite opzioni come precedentemente menzionato. Gli stili incorporati hanno la precedenza sulle regole CSS esterne; la miscelazione dei due è scoraggiata, poiché potrebbe richiedere molto tempo allo sviluppatore di capire perché le loro regole CSS non vengono rispettate dagli elementi creati dal tuo plugin. Usa il tuo miglior giudizio in questi casi.
Come regola generale, i CSS incorporati non funzionano correttamente, a meno che non siano così minimali da non giustificare il proprio foglio di stile esterno.
La prova è nel pudding: se non puoi fornire un esempio pratico di ciò che il tuo plug-in fa con il codice di accompagnamento, le persone saranno presto disattivate a usare il tuo plugin. Semplice come quella. Non essere pigro.
Un buon modello per esempi:
jQuery, come ogni buona libreria di codici, cresce ad ogni rilascio. La maggior parte dei metodi viene mantenuta anche dopo che il supporto è stato ritirato. Tuttavia, vengono aggiunti nuovi metodi; un perfetto esempio di questo è il .sopra()
metodo, che è la nuova soluzione all-in-one di jQuery per la delega degli eventi. Se scrivi un plugin che usa .sopra()
, le persone che usano jQuery 1.6 o versioni precedenti saranno sfortunate. Ora non sto suggerendo di codificare per il minimo comune denominatore, ma, nella tua documentazione, assicurati di spiegare quale versione di jQuery supporta il tuo plugin. Se si introduce un plug-in con supporto per jQuery 1.7, si consiglia vivamente di mantenere il supporto per 1.7 anche dopo l'uscita di 1.8. Dovresti anche considerare di sfruttare le nuove funzionalità / migliori / più veloci in jQuery man mano che escono.
Incoraggia gli sviluppatori ad aggiornare, ma non rompere il tuo plugin troppo spesso! Un'opzione consiste nell'offrire versioni "obsolete" obsolete e non supportate del tuo plug-in.
È ora di mordere il proiettile se non hai ancora imparato a usare il controllo di versione.
Oltre a mantenere il supporto / compatibilità della versione jQuery parte della documentazione, dovresti anche lavorare nel controllo della versione. Il controllo della versione (in particolare, tramite GitHub) è in gran parte la sede della codifica sociale. Se si sta sviluppando un plugin per jQuery che si desidera pubblicare nel repository ufficiale, deve comunque essere memorizzato in un repository GitHub; è ora di mordere il proiettile se non hai imparato come usare il controllo di versione. Ci sono innumerevoli benefici per il controllo della versione, che vanno oltre lo scopo di questo articolo. Ma uno dei principali vantaggi è che consente alle persone di visualizzare le modifiche, i miglioramenti e le correzioni di compatibilità che si effettuano e quando vengono creati. Questo apre anche la parola per il contributo e la personalizzazione / estensione dei plugin che scrivi.
Il mondo non ha bisogno di un altro plug-in di slider.
Ok, l'abbiamo ignorato abbastanza a lungo qui: alcuni "plug-in" sono inutili o troppo superficiali per essere chiamati plugin. Il mondo non ha bisogno di un altro plug-in di slider! Va notato, tuttavia, che i team interni possono sviluppare i propri plugin per i propri usi, il che è perfettamente corretto. Tuttavia, se speri di spingere il tuo plugin nella sfera del social coding, trova un motivo per scrivere altro codice. Come dice il proverbio, non c'è motivo di reinventare la ruota. Invece, prendi la ruota di qualcun altro e costruisci una macchina da corsa. Certo, a volte ci sono modi nuovi e migliori di fare le stesse cose che sono già state fatte. Ad esempio, potresti scrivere un nuovo plug-in di slider se stai utilizzando una tecnologia più veloce o nuova.
Questo è abbastanza semplice: offri una versione minificata del tuo codice. Questo lo rende più piccolo e più veloce. Garantisce inoltre che il tuo Javascript sia privo di errori al momento della compilazione. Quando riduci il codice, non dimenticare di offrire anche la versione non compressa, in modo che i tuoi colleghi possano rivedere il codice sottostante. Esistono strumenti gratuiti ed economici per sviluppatori front-end di tutti i livelli di esperienza.
Fare riferimento al numero di punta 13 per una soluzione automatizzata.
Quando scrivi un plugin, è pensato per essere usato da altri, giusto? Per questo motivo, il codice sorgente più efficace è altamente leggibile. Se stai scrivendo innumerevoli funzioni di stile lambda one-liner intelligenti, o se i nomi delle variabili non sono semantici, sarà difficile eseguire il debug degli errori quando si verificano inevitabilmente. Invece di scrivere nomi di variabili brevi per risparmiare spazio, segui il consiglio nella punta numero nove (minify!). Questa è un'altra parte della buona documentazione; gli sviluppatori decenti dovrebbero essere in grado di rivedere il codice e capire cosa fa senza dover spendere troppe energie.
Se ti ritrovi a chiamare variabili "
un
" o "X
", lo stai facendo male.
Inoltre, se ti ritrovi a consultare la documentazione per ricordare cosa il tuo sta facendo un codice strano, è anche probabile che sia meno conciso e più esplicativo. Limita il numero di righe in ciascuna funzione al minor numero possibile di righe; se si allungano per trenta o più linee, potrebbe esserci un odore di codice.
Per quanto ci piaccia usare jQuery, è importante capire che si tratta di una libreria e che viene fornita con un piccolo costo. In generale, non è necessario preoccuparsi troppo di cose come le prestazioni del selettore jQuery. Non essere odioso, e starai bene. jQuery è altamente ottimizzato. Detto questo, se l'unica ragione per cui hai bisogno di jQuery (o di un plugin) è di eseguire alcune query sul DOM, potresti prendere in considerazione la rimozione completa dell'astrazione e, invece, attenersi a vanilla JavaScript o Zepto.
Nota: se decidi di restare con JavaScript vaniglia, assicurati di utilizzare metodi che sono cross-browser. Potresti aver bisogno di un piccolo polyfill per le nuove API.
Usa Grunt. Periodo.
Grunt è uno "strumento di creazione da riga di comando basato su attività per progetti JavaScript", che è stato trattato in dettaglio qui di recente su Nettuts +. Ti permette di fare cose come questa:
grunt init: jquery
Questa riga (eseguita nella riga di comando) ti richiederà una serie di domande, come titolo, descrizione, versione, repository git, licenze, eccetera. Queste informazioni aiutano ad automatizzare il processo di impostazione della documentazione, delle licenze, ecc.
Grunt fa molto di più che semplicemente creare un codice standard per la tua caldaia; offre anche strumenti integrati, come il lager di codice JSHint, e può automatizzare i test QUnit per te finché hai installato PhantomJS (di cui Grunt si occupa). In questo modo, è possibile semplificare il flusso di lavoro, poiché i test vengono eseguiti immediatamente nel terminale al momento del salvataggio.
Oh, a proposito - tu fare prova il tuo codice, giusto? In caso contrario, come si può garantire / dichiarare che il codice funzioni come previsto? Il test manuale ha il suo posto, ma, se ti ritrovi a rinfrescare il browser innumerevoli volte ogni ora, stai sbagliando. Prendi in considerazione l'utilizzo di strumenti come QUnit, Jasmine o anche Mocha.
Il test è particolarmente utile quando si uniscono richieste pull su GitHub. È possibile richiedere che tutte le richieste forniscano test per garantire che il nuovo codice modificato non interrompa il plug-in esistente.
Se il concetto di test dei plugin jQuery è nuovo di zecca per te, prova a guardare il nostro esclusivo screencast Premium, Techniques For Test-Driving jQuery Plugin. Inoltre, stiamo lanciando un nuovo corso "JavaScript Testing With Jasmine" alla fine di questa settimana sul sito!
Non ti faremo alcun favore semplicemente dicendoti che cosa stai sbagliando. Ecco alcuni link che ti aiuteranno a tornare sulla giusta strada!
Se stai scrivendo un plugin jQuery, è fondamentale allontanarti dalle insidie elencate sopra. Ho perso qualche segno chiave di un plugin mal eseguito?