jQuery外掛程式開發精品教程讓你的jQuery提升一個台階,jquery精品
要說jQuery 最成功的地方,我認為是它的可擴充性吸引了眾多開發人員為其開發外掛程式,從而建立起了一個生態系統。這好比大公司們爭相做平台一樣,得平台者得天下。蘋果,微軟,Google等巨頭,都有各自的平台及生態圈。
學會使用jQuery並不難,因為它簡單易學,並且相信你接觸jQuery後肯定也使用或熟悉了不少其外掛程式。如果要將能力上升一個台階,編寫一個屬於自己的外掛程式是個不錯的選擇。
本教程可能不是最精品的,但一定是最細緻的。
jQuery外掛程式開發模式
軟體開發過程中是需要一定的設計模式來指導開發的,有了模式,我們就能更好地組織我們的代碼,並且從這些前人總結出來的模式中學到很多好的實踐。
根據《jQuery進階編程》的描述,jQuery外掛程式開發方式主要有三種:
1.通過$.extend()來擴充jQuery
2.通過$.fn 向jQuery添加新的方法
3.通過$.widget()應用jQuery UI的組件工廠方式建立
通常我們使用第二種方法來進行簡單外掛程式開發,說簡單是相對於第三種方式。第三種方式是用來開發更進階jQuery組件的,該模式開發出來的組件帶有很多jQuery內建的特性,比如外掛程式的狀態資訊自動儲存,各種關於外掛程式的常用方法等,非常貼心,這裡不細說。
而第一種方式又太簡單,僅僅是在jQuery命名空間或者理解成jQuery身上添加了一個靜態方法而以。所以我們調用通過$.extend()添加的函數時直接通過$符號調用($.myfunction())而不需要選中DOM元素($('#example').myfunction())。請看下面的例子。
$.extend({sayHello: function(name) {console.log('Hello,' + (name ? name : 'Dude') + '!');}})$.sayHello(); //調用$.sayHello('Wayou'); //帶參調用
運行結果:
上面代碼中,通過$.extend()向jQuery添加了一個sayHello函數,然後通過$直接調用。到此你可以認為我們已經完成了一個簡單的jQuery外掛程式了。
但如你所見,這種方式用來定義一些輔助方法是比較方便的。比如一個自訂的console,輸出特定格式的資訊,定義一次後可以通過jQuery在程式中任何需要的地方調用它。
$.extend({log: function(message) {var now = new Date(),y = now.getFullYear(),m = now.getMonth() + 1, //!JavaScript中月分是從0開始的d = now.getDate(),h = now.getHours(),min = now.getMinutes(),s = now.getSeconds(),time = y + '/' + m + '/' + d + ' ' + h + ':' + min + ':' + s;console.log(time + ' My App: ' + message);}})$.log('initializing...'); //調用
但這種方式無法利用jQuery強大的選取器帶來的便利,要處理DOM元素以及將外掛程式更好地運用於所選擇的元素身上,還是需要使用第二種開發方式。你所見到或使用的外掛程式也大多是通過此種方式開發。
外掛程式開發
下面我們就來看第二種方式的jQuery外掛程式開發。
基本方法
先看一下它的基本格式:
$.fn.pluginName = function() {//your code goes here}
基本上就是往$.fn上面添加一個方法,名字是我們的外掛程式名稱。然後我們的外掛程式代碼在這個方法裡面展開。
比如我們將頁面上所有連結顏色轉成紅色,則可以這樣寫這個外掛程式:
$.fn.myPlugin = function() {//在這裡面,this指的是用jQuery選中的元素//example :$('a'),則this=$('a')this.css('color', 'red');}
在外掛程式名字定義的這個函數內部,this指代的是我們在調用該外掛程式時,用jQuery選取器選中的元素,一般是一個jQuery類型的集合。比如$('a')返回的是頁面上所有a標籤的集合,且這個集合已經是jQuery封裝類型了,也就是說,在對其進行操作的時候可以直接調用jQuery的其他方法而不需要再用貨幣符號來封裝一下。
所以在上面外掛程式代碼中,我們在this身上調用jQuery的css()方法,也就相當於在調用 $('a').css()。
理解this在這個地方的含義很重要。這樣你才知道為什麼可以直接商用jQuery方法同時在其他地方this指代不同時我們又需要用jQuery重新封裝才能調用,下面會講到。初學容易被this的值整暈,但理解了就不難。
現在就可以去頁面試試我們的代碼了,在頁面上放幾個連結,調用外掛程式後連結字型變成紅色。
<ul><li><a href="http://www.webo.com/liuwayong">我的微博</a></li><li><a href="http://http://www.cnblogs.com/Wayou/">我的部落格</a></li><li><a href="http://wayouliu.duapp.com/">我的小站</a></li></ul><p>這是p標籤不是a標籤,我不會受影響</p><script src="jquery-1.11.0.min.js"></script><script src="jquery.myplugin.js"></script><script type="text/javascript">$(function(){$('a').myPlugin();})</script>
運行結果:
下面進一步,在外掛程式代碼裡處理每個具體的元素,而不是對一個集合進行處理,這樣我們就可以針對每個元素進行相應操作。
我們已經知道this指代jQuery選取器返回的集合,那麼通過調用jQuery的.each()方法就可以處理合集中的每個元素了,但此刻要注意的是,在each方法內部,this指帶的是普通的DOM元素了,如果需要調用jQuery的方法那就需要用$來重新封裝一下。
比如現在我們要在每個連結顯示連結的真真實位址,首先通過each遍曆所有a標籤,然後擷取href屬性的值再加到連結文本後面。
更改後我們的外掛程式代碼為:
$.fn.myPlugin = function() {//在這裡面,this指的是用jQuery選中的元素this.css('color', 'red');this.each(function() {//對每個元素進行操作$(this).append(' ' + $(this).attr('href'));}))}
調用代碼還是一樣的,我們通過選中頁面所有的a標籤來調用這個外掛程式
運行結果:
到此,你已經可以編寫功能簡單的jQuery外掛程式了。是不是也沒那麼難。
下面開始jQuery外掛程式編寫中一個重要的部分,參數的接收。
支援鏈式調用
我們都知道jQuery一個時常優雅的特性是支援鏈式調用,選擇好DOM元素後可以不斷地調用其他方法。
要讓外掛程式不打破這種鏈式調用,只需return一下即可。
$.fn.myPlugin = function() {//在這裡面,this指的是用jQuery選中的元素this.css('color', 'red');return this.each(function() {//對每個元素進行操作$(this).append(' ' + $(this).attr('href'));}))}
讓外掛程式接收參數
一個強勁的外掛程式是可以讓使用者隨意定製的,這要求我們提供在編寫外掛程式時就要考慮得全面些,盡量提供合適的參數。
比如現在我們不想讓連結只變成紅色,我們讓外掛程式的使用者自己定義顯示什麼顏色,要做到這一點很方便,只需要使用者在調用的時候傳入一個參數即可。同時我們在外掛程式的代碼裡面接收。另一方面,為了靈活,使用者可以不傳遞參數,外掛程式裡面會給出參數的預設值。
在處理外掛程式參數的接收上,通常使用jQuery的extend方法,上面也提到過,但那是給extend方法傳遞單個對象的情況下,這個對象會合并到jQuery身上,所以我們就可以在jQuery身上調用新合并對象裡包含的方法了,像上面的例子。當給extend方法傳遞一個以上的參數時,它會將所有參數對象合并到第一個裡。同時,如果對象中有同名屬性時,合并的時候後面的會覆蓋前面的。
利用這一點,我們可以在外掛程式裡定義一個儲存外掛程式參數預設值的對象,同時將接收來的參數對象合并到預設對象上,最後就實現了使用者指定了值的參數使用指定的值,未指定的參數使用外掛程式預設值。
為了示範方便,再指定一個參數fontSize,允許調用外掛程式的時候設定字型大小。
$.fn.myPlugin = function(options) {var defaults = {'color': 'red','fontSize': '12px'};var settings = $.extend(defaults, options);return this.css({'color': settings.color,'fontSize': settings.fontSize});}
現在,我們調用的時候指定顏色,字型大小未指定,會運用外掛程式裡的預設值12px。
$('a').myPlugin({'color': '#2C9929'});
運行結果:
同時指定顏色與字型大小:
$('a').myPlugin({'color': '#2C9929','fontSize': '20px'});
保護好預設參數
注意到上面代碼調用extend時會將defaults的值改變,這樣不好,因為它作為外掛程式因有的一些東西應該維持原樣,另外就是如果你在後續代碼中還要使用這些預設值的話,當你再次訪問它時它已經被使用者傳進來的參數更改了。
一個好的做法是將一個新的Null 物件做為$.extend的第一個參數,defaults和使用者傳遞的參數對象緊隨其後,這樣做的好處是所有值被合并到這個Null 物件上,保護了外掛程式裡面的預設值。
$.fn.myPlugin = function(options) {var defaults = {'color': 'red','fontSize': '12px'};var settings = $.extend({},defaults, options);//將一個Null 物件做為第一個參數return this.css({'color': settings.color,'fontSize': settings.fontSize});}
到此,外掛程式可以接收和處理參數後,就可以編寫出更健壯而靈活的外掛程式了。若要編寫一個複雜的外掛程式,代碼量會很大,如何組織代碼就成了一個需要面臨的問題,沒有一個好的方式來組織這些代碼,整體感覺會雜亂無章,同時也不好維護,所以將外掛程式的所有方法屬性包裝到一個對象上,用物件導向的思維來進行開發,無疑會使工作輕鬆很多。
物件導向的外掛程式開發
為什麼要有物件導向的思維,因為如果不這樣,你可能需要一個方法的時候就去定義一個function,當需要另外一個方法的時候,再去隨便定義一個function,同樣,需要一個變數的時候,毫無規則地定義一些散落在代碼各處的變數。
還是老問題,不方便維護,也不夠清晰。當然,這些問題在代碼規模較小時是體現不出來的。
如果將需要的重要變數定義到對象的屬性上,函數變成對象的方法,當我們需要的時候通過對象來擷取,一來方便管理,二來不會影響外部命名空間,因為所有這些變數名還有方法名都是在對象內部。
接著上面的例子,我們可以把這個外掛程式抽象成一個美化頁面的對象,因為他的功能是設定顏色啊字型啊什麼的,當然我們還可以加入其他功能比如設定底線啊什麼的。當然對於這個例子抽象成對象有點小題大做,這裡僅作示範用。以後我可能會介紹我編寫的一個jQuery外掛程式SlipHover,其中代碼就比較多,這樣的模式就用得上了。
所以我們建立一個對象命名為Beautifier,然後我們在外掛程式裡使用這個對象來編碼。
//定義Beautifier的建構函式var Beautifier = function(ele, opt) {this.$element = ele,this.defaults = {'color': 'red','fontSize': '12px','textDecoration':'none'},this.options = $.extend({}, this.defaults, opt)}//定義Beautifier的方法Beautifier.prototype = {beautify: function() {return this.$element.css({'color': this.options.color,'fontSize': this.options.fontSize,'textDecoration': this.options.textDecoration});}}//在外掛程式中使用Beautifier對象$.fn.myPlugin = function(options) {//建立Beautifier的實體var beautifier = new Beautifier(this, options);//調用其方法return beautifier.beautify();}
通過上面這樣一改造,我們的代碼變得更物件導向了,也更好維護和理解,以後要加新功能新方法,只需向對象添加新變數及方法即可,然後在外掛程式裡執行個體化後即可調用新添加的東西。
外掛程式的調用還是一樣的,我們對代碼的改動並不影響外掛程式其他地方,只是將代碼的組織圖改動了而以。
$(function() {$('a').myPlugin({'color': '#2C9929','fontSize': '20px'});})
指定文字帶底線(我們在Beautifier對象中新加的功能,預設不帶底線,如上面的例子)的調用:
$(function() {$('a').myPlugin({'color': '#2C9929','fontSize': '20px','textDecoration': 'underline'});})
到這裡,你可以更好地編寫複雜的外掛程式同時很好地組織代碼了。當我們回頭去看上面的代碼時,其實也還是有改進空間的。也就是下面介紹的關於命名空間及變數各什麼的,一些雜項。
關於命名空間
不僅僅是jQuery外掛程式的開發,我們在寫任何JS代碼時都應該注意的一點是不要汙染全域命名空間。因為隨著你代碼的增多,如果有意無意在全域範圍內定義一些變數的話,最後很難維護,也容易跟別人寫的代碼有衝突。
比如你在代碼中向全域window對象添加了一個變數status用於存放狀態,同時頁面中引用了另一個別人寫的庫,也向全域添加了這樣一個同名變數,最後的結果肯定不是你想要的。所以不到萬不得已,一般我們不會將變數定義成全域的。
一個好的做法是始終用自調用匿名函數包裹你的代碼,這樣就可以完全放心,安全地將它用於任何地方了,絕對沒有衝突。
用自調用匿名函數包裹你的代碼
我們知道JavaScript中無法用花括弧方便地建立範圍,但函數卻可以形成一個範圍,域內的代碼是無法被外界訪問的。如果我們將自己的代碼放入一個函數中,那麼就不會汙染全域命名空間,同時不會和別的代碼衝突。
如上面我們定義了一個Beautifier全域變數,它會被附到全域的window對象上,為了防止這種事情發生,你或許會說,把所有代碼放到jQuery的外掛程式定義代碼裡面去啊,也就是放到$.fn.myPlugin裡面。這樣做倒也是種選擇。但會讓我們實際跟外掛程式定義有關的代碼變得臃腫,而在$.fn.myPlugin裡面我們其實應該更專註於外掛程式的調用,以及如何與jQuery互動。
所以保持原來的代碼不變,我們將所有代碼用自調用匿名函數包裹。
(function() {//定義Beautifier的建構函式var Beautifier = function(ele, opt) {this.$element = ele,this.defaults = {'color': 'red','fontSize': '12px','textDecoration': 'none'},this.options = $.extend({}, this.defaults, opt)}//定義Beautifier的方法Beautifier.prototype = {beautify: function() {return this.$element.css({'color': this.options.color,'fontSize': this.options.fontSize,'textDecoration': this.options.textDecoration});}}//在外掛程式中使用Beautifier對象$.fn.myPlugin = function(options) {//建立Beautifier的實體var beautifier = new Beautifier(this, options);//調用其方法return beautifier.beautify();}})();
這樣做的好處,也就是上面所闡述的那樣。另外還有一個好處就是,自調用匿名函數裡面的代碼會在第一時間執行,頁面準備好過後,上面的代碼就將外掛程式準備好了,以方便在後面的代碼中使用外掛程式。
目前為止似乎接近完美了。如果再考慮到其他一些因素,比如我們將這段代碼放到頁面後,前面別人寫的代碼沒有用分號結尾,或者前面的代碼將window, undefined等這些系統變數或者關鍵字修改掉了,正好我們又在自己的代碼裡面進行了使用,那結果也是不可預測的,這不是 我們想要的。我知道其實你還沒太明白,下面詳細介紹。
將系統變數以變數形式傳遞到外掛程式內部
來看下面的代碼,你猜他會出現什麼結果?
var foo=function(){//別人的代碼}//注意這裡沒有用分號結尾//開始我們的代碼。。。(function(){//我們的代碼。。alert('Hello!');})();
本來別人的代碼也正常工作,只是最後定義的那個函數沒有用分號結尾而以,然後當頁面中引入我們的外掛程式時,報錯了,我們的代碼無法正常執行。
原因是我們用來充當自調用匿名函數的第一對括弧與上面別人定義的函數相連,因為中間沒有分號嘛,總之我們的代碼無法正常解析了,所以報錯。
所以好的做法是我們在代碼開頭加一個分號,這在任何時候都是一個好的習慣。
var foo=function(){//別人的代碼}//注意這裡沒有用分號結尾//開始我們的代碼。。。;(function(){//我們的代碼。。alert('Hello!');})();
同時,將系統變數以參數形式傳遞到外掛程式內部也是個不錯的實踐。
當我們這樣做之後,window等系統變數在外掛程式內部就有了一個局部的引用,可以提高訪問速度,會有些許效能的提升
最後我們得到一個非常安全結構良好的代碼:
;(function($,window,document,undefined){//我們的代碼。。//blah blah blah...})(jQuery,window,document);
而至於這個undefined,稍微有意思一點,為了得到沒有被修改的undefined,我們並沒有傳遞這個參數,但卻在接收時接收了它,因為實際並沒有傳,所以‘undefined'那個位置接收到的就是真實的'undefined'了。是不是有點hack的味道,值得細細體會的技術,當然不是我發明的,都是從前人的經驗中學習。
所以最後我們的外掛程式成了這樣:
;(function($, window, document,undefined) {//定義Beautifier的建構函式var Beautifier = function(ele, opt) {this.$element = ele,this.defaults = {'color': 'red','fontSize': '12px','textDecoration': 'none'},this.options = $.extend({}, this.defaults, opt)}//定義Beautifier的方法Beautifier.prototype = {beautify: function() {return this.$element.css({'color': this.options.color,'fontSize': this.options.fontSize,'textDecoration': this.options.textDecoration});}}//在外掛程式中使用Beautifier對象$.fn.myPlugin = function(options) {//建立Beautifier的實體var beautifier = new Beautifier(this, options);//調用其方法return beautifier.beautify();}})(jQuery, window, document);
一個安全,結構良好,組織有序的外掛程式編寫完成。
關於變數定義及命名
現在談談關於變數及方法等的命名,沒有硬性規定,但為了規範,遵循一些約定還是很有必要的。
變數定義:好的做法是把將要使用的變數名用一個var關鍵字一併定義在代碼開頭,變數名間用逗號隔開。原因有二:
•一是便於理解,知道下面的代碼會用到哪些變數,同時代碼顯得整潔且有規律,也方便管理,變數定義與邏輯代碼分開;
•二是因為JavaScript中所有變數及函數名會自動提升,也稱之為JavaScript的Hoist特性,即使你將變數的定義穿插在邏輯代碼中,在代碼解析運行期間,這些變數的聲明還是被提升到了當前範圍最頂端的,所以我們將變數定義在一個範圍的開頭是更符合邏輯的一種做法。當然,再次說明這隻是一種約定,不是必需的。
變數及函數命名 一般使用駝峰命名法(CamelCase),即首個單詞的首字母小寫,後面單字首大寫,比如resultArray,requestAnimationFrame。對於常量,所有字母採用大寫,多個單詞用底線隔開,比如WIDTH=100,BRUSH_COLOR='#00ff00'。當變數是jQuery類型時,建議以$開頭,開始會不習慣,但經常用了之後會感覺很方便,因為可以很方便地將它與普通變數區別開來,一看到以$開頭我們就知道它是jQuery類型可以直接在其身上調用jQuery相關的方法,比如var $element=$('a'); 之後就可以在後面的代碼中很方便地使用它,並且與其他變數容易區分開來。
引號的使用:既然都扯了這些與外掛程式主題無關的了,這裡再多說一句,一般HTML代碼裡面使用雙引號,而在JavaScript中多用單引號,比如下面代碼所示:
var name = 'Wayou';document.getElementById(‘example').innerHTML = '< a href="http: //wayouliu.duapp.com/">'+name+'</a>'; //href=".." HTML中保持雙引號,JavaScript中保持單引號
一方面,HTML代碼中本來就使用的是雙引號,另一方面,在JavaScript中引號中還需要引號的時候,要求我們單雙引號間隔著寫才是合法的語句,除非你使用轉意符那也是可以的。再者,堅持這樣的統一可以保持代碼風格的一致,不會出現這裡字串用雙引號包著,另外的地方就在用單引號。
代碼混淆與壓縮
進行完上面的步驟,已經小有所成了。或許你很早就注意到了,你下載的外掛程式裡面,一般都會提供一個壓縮的版本一般在檔案名稱裡帶個'min'字樣。也就是minified的意思,壓縮濃縮後的版本。並且平時我們使用的jQuery也是官網提供的壓縮版本,jquery.min.js。
這裡的壓縮不是指代碼進行功能上的壓縮,而是通過將代碼裡面的變數名,方法函數名等等用更短的名稱來替換,並且刪除注釋(如果有的話)刪除代碼間的空白及換行所得到的濃縮版本。同時由於代碼裡面的各種名稱都已經被替代,別人無法閱讀和分清其邏輯,也起到了混淆代碼的作用。
壓縮的好處
•源碼經過混淆壓縮後,體積大大減小,使代碼變得輕量級,同時加快了下載速度,兩面載入變快。比如正常jQuery v1.11.0的源碼是276kb,而壓縮後的版本僅94.1kb!體積減小一半還多。這個體積的減小對於檔案下載速度的提升不可小覷。
•經過壓縮混淆後,代碼還能閱讀嘛?當然不能,所以順帶還起到了代碼保護的作用。當然只是針對你編寫了一些比較酷的代碼又不想別人抄襲的情況。對於jQuery社區,這裡本身就是開源的世界,同時JavaScript這東西其實也沒什麼實質性方法可以防止別人查看閱讀你的代碼,畢竟有混淆就有反混淆工具,這裡代碼壓縮更多的還是上面提到的壓縮檔的作用,同時一定程度上防止別人抄襲。
工具
所使用的工具推崇的是Google開發的Closure Compiler。該工具需要Java環境的支援,所以使用前你可能需要先在機子上裝JRE, 然後再擷取Closure進行使用。
同時也有很朋線上的代碼混淆壓縮公用程式,用起來也很方便。這些工具都是一搜一大把的。
外掛程式發布
這一步不是必需的,但本著把事情做完整的態度,同時你也許也希望有更多人看到或使用你的外掛程式吧。
•首先你需要將外掛程式代碼放到GitHub上建立一個Service Hook,這樣做的目的是你以後更新的外掛程式後,jQuery可以自動去擷取新版本的資訊然後展示在外掛程式中心的頁面上。關於如何傳代碼到GitHub,你去下載GitHub 提供的用戶端工具,就會知道如何操作了,非常方便。關於在GitHub建立Service Hook,也只是點幾下而以的事情。下面會介紹。
•然後需要製作一個JSON格式的資訊清單檔,其中包括關於外掛程式的基本資料,具體格式及參數可以在jQuery官網外掛程式發布指南頁面瞭解到,這裡提供一個樣本檔案,是我之前寫的一個jQuery外掛程式SlipHover:
{"name": "sliphover","title": "SlipHover","description": "Apply direction aware 2D/3D hover effect to images","keywords": ["direction-aware","animation","effect","hover","image","overlay","gallery"],"version": "1.1.1","author": {"name": "Wayou","email": "liuwayong@gmail.com","url": "https://github.com/Wayou"},"maintainers": [{"name": "Wayou","email": "liuwayong@gmail.com","url": "https://github.com/Wayou"}],"licenses": [{"type": "MIT","url": "https://github.com/jquery/jquery-color/blob/2.1.2/MIT-LICENSE.txt"}],"bugs": "https://github.com/Wayou/sliphover/issues","homepage": "http://wayou.github.io/SlipHover/","docs": "http://wayou.github.io/SlipHover/","demo":"http://wayou.github.io/SlipHover/","download": "https://github.com/Wayou/SlipHover/zipball/master","dependencies": {"jquery": ">=1.5"}}
•然後就可以在外掛程式的根目錄執行現行git代碼來發布外掛程式了。其中0.1.0是版本號碼,以後每次你的外掛程式有新版本發布只需更新上面命令中的版本,建立新的tag,這樣jQuery外掛程式中心就會自動擷取到新版本資訊了
$ git tag 0.1.0$ git push origin --tags
GitHub Service Hook
1 點擊項目右邊菜單的設定
2進入設定頁面後點擊'Webhooks & Services '
3然後點擊右邊首頁面上的'Configure services' 按鈕
4這時出現一個很長的列表,向下找到jQuery Plugins 點擊
5點擊選中框後點擊'更新設定'按鈕
到此就設定完成了。
您可能感興趣的文章:
- 自己動手開發jQuery外掛程式教程
- jQuery外掛程式開發詳細教程
- jQuery zclip外掛程式實現跨瀏覽器複製功能
- jQuery外掛程式實現靜態HTML驗證碼校正
- jQuery外掛程式開發精品教程(讓你的jQuery更上一個台階)