Writing Your Own jQuery Pluginsjavascript
原文地址:http://blog.teamtreehouse.com/writing-your-own-jquery-pluginscss
jQuery是一個優秀的javascript庫。它不但擁有良好的跨瀏覽器兼容性,容易學習掌握,還能夠垂手可得的爲你的網站添加有趣的交互。同時,大量的jQuery插件可以讓你爲所欲爲的完成你想要完成的工做。java
然而在日常的工做中,並非總可以找到能夠徹底知足需求的插件,或者你想要將一些經常使用的功能封裝以便保證項目的可重用性。在這些情形下,編寫本身的jQuery插件是一個很好的知足需求的手段。jquery
其實,編寫jQuery插件並無想像中難。這篇文章,咱們將經過編寫一個簡單的插件,爲其添加一些參數和事件回調,來向你完整的展現整個流程。git
像大多數編程指南的開篇同樣,咱們也以一個「Hello World」插件開始吧。在開始以前,先建立必要的文件並在HTML文檔中引用它們。首先,在站點的js目錄下新建插件文件jquery.hello-world.js。一般,jQuery插件的命名以「jquery.」開始。github
接下來,須要在HTML文件中連接插件文件及其依賴的jquery核心庫。咱們將如下兩行放置在文檔的底部,也即</body>標籤以前。編程
<script src="js/jquery-1.9.1.min.js"></script> <script src="js/jquery.hello-world.js"></script>
jQuery自己已經爲插件開發提供了足夠的支持。但咱們依然須要遵循JavaScript開發的最佳實踐,將全部的代碼都囊括在一個本地做用域中。下面是一個常規的jQuery插件基礎結構:瀏覽器
(function($) { $.fn.helloWorld = function() { // Future home of "Hello, World!" } }(jQuery));
讓咱們花一點時間來理解一下上述代碼的含義。經過將全部代碼包含在 (function() {}) 自執行代碼塊中,可以保證插件內部的全部變量不會污染到全局變量。畢竟,咱們確定不肯意看到編寫的插件和頁面中的其它JavaScript代碼發生衝突。函數
可能你已經注意到,咱們定義插件的方式,就好像jQuery也位於其「無衝突」模式。再一次強調,咱們須要避免插件與頁面中其它JavaScript發生衝突,這也包括使用到的'$'符號。該符號頗有可能被其它的JavaScript庫使用。學習
最後,$.fn這種寫法是jQuery定義插件的方式。這裏將其命名爲helloWorld並將全部代碼放置在該函數中。下面,讓咱們作一些真正有意義的工做。
爲了使插件的代碼儘量的簡單,同時又能達到演示的目的,咱們將要完成的功能是改變關聯的元素的文本內容爲「hello world」。這已經近乎於傻瓜式的操做了。
(function($) { $.fn.helloWorld = function() { this.each( function() { $(this).text("Hello, World!"); }); } }(jQuery));
當在jQuery選擇器上調用上述插件時,關聯的元素已是一個jQuery對象,所以再也不須要再用"$(this)"結構進行包裝。然而,若是須要在一個循環中使用每個匹配的元素,好比$.each(),則通常會使用$(this)對循環的元素進行包裝。
假如咱們想要改變下面頁面中全部的<h2>標題的文本:
調用的方式你已經很熟悉了,就像這樣:
<script> $(document).ready( function() { $('h2').helloWorld(); }); </script>
結果爲:
咱們能作的遠遠不止如此。當上面的插件調用時,實際上徹底被隔離在了它自己的做用域。也就是說,調用的做用鏈在插件內部被終止了。若是你試着以jQuery的鏈式寫法調用其它操做時,是不會生效的。爲了修復這個問題,須要確保返回每一個DOM元素循環後的結果:
(function($) { $.fn.helloWorld = function() { return this.each( function() { $(this).text("Hello, World!"); }); } }(jQuery));
恭喜你,已經寫出了你人生中的第一個jQuery插件!
如今你可能正沉浸在編寫出本身的jQuery插件的喜悅中,這時候你的老大跑過來講,想要把如今的網站翻譯成西班牙語。老天爺,如今該咋整?
其實,能夠簡單的添加一個參數完成上述需求。從新審視上述插件的代碼,咱們能夠替換其內部的硬編碼文本內容爲一個變量,在調用的時候傳入該變量的值。
(function($) { $.fn.helloWorld = function( customText ) { return this.each( function() { $(this).text( customText ); }); } }(jQuery));
如你所見,在調用的時候能夠傳入任何想要傳入的文本值。辦公室的馬德里先生已經將咱們須要的東西翻譯成了西班牙語,如今可使用參數的方式調用該插件:
<script> $(document).ready( function() { $('h2').helloWorld('¡Hola, mundo!'); }); </script>
頁面呈現以下:
可能你已經感受到一點擔心,若是在調用插件的時候沒有傳入文本怎麼辦?顯而易見,頁面中匹配的元素的文本會被插件修改成空值,這可能不是咱們預期的結果。另外,咱們的老大已經跑過來要求添加一個變量,若是他再跑過來要求添加更多的可定製化的選項怎麼辦?不斷的添加參數畢竟不是長遠之計,一勞永逸的解決方法是經過options對象。
咱們已經知道具體的文本內容須要由外部傳入,如今,老大又要求文本顏色和字體大小一樣在調用時指定(好吧,我知道顏色和字體大小均可以經過jQuery內置的函數進行控制,這裏僅僅是一個演示)。讓咱們爲插件添加一個options參數對象,同時經過$.extend方法與默認的參數進行合併:
(function($) { $.fn.helloWorld = function( options ) { // Establish our default settings var settings = $.extend({ text : 'Hello, World!', color : null, fontStyle : null }, options); return this.each( function() { // We'll get back to this in a moment }); } }(jQuery));
如今咱們有了可供外部設置的選項。若是調用的時候缺乏了待替換的文本,將會使用指定的默認值。另外,在配置參數中添加了"color"和"fontStyle"兩個屬性,默認值均爲"null"。若是在CSS文件中已經定義了顏色值和字體大小,在插件調用時不須要再重複指定。固然,兩者都可以在插件內部重寫。代碼以下:
return this.each( function() { $(this).text( settings.text ); if ( settings.color ) { $(this).css( 'color', settings.color ); } if ( settings.fontStyle ) { $(this).css( 'font-style', settings.fontStyle ); } });
由於該插件的目的是替換文本。若是提供的文本值爲空則沒有任何意義,這也是在插件內部爲其指定默認值的緣由,當參數缺失時顯示缺省值總比空白要好得多。另外一方面,顏色值和字體風格則只須要提供一個可供重寫的入口。
這時候老大跑過來講想要將站點翻譯爲法語,另外還但願將文本顏色改成藍色,字體調整爲italic。幸運的是,咱們的插件處理這些需求毫無壓力:
$('h2').helloWorld({ text : 'Salut, le monde!', color : '#005dff', fontStyle : 'italic' });
你看,咱們的插件已經擁有了一些由外部控制的參數。未來能夠在不影響現有調用的基礎上,很是容易的添加或去掉某個參數。這些都益於良好的可擴展性。
但咱們的老大帶着另一個需求再一次跑了過來:一旦插件按其預約的方式調用完畢,應該彈出一個對話框通知用戶這個消息。爲了達到這個目的,有兩個選擇:要麼辭職,由於這個傢伙明顯無視最初的需求文檔。要麼不走這麼極端的路線,爲咱們的插件添加處理回調函數的能力。
回調函數是JavaScript函數的參數,同時它自己也是一個JavaScript函數。其並非jQuery獨有的特性。初看上去回調函數是一個複雜的概念,但實際它的使用很是簡單。
咱們須要作的僅僅是在配置對象中附加一個額外的參數:
// Establish our default settings var settings = $.extend({ text : 'Hello, World!', color : null, fontStyle : null, complete : null }, options);
如今,當插件調用完畢時,就該附加的「complete」參數生效了。爲了調用該參數,首先須要確保其是一個真正的函數。幸運的是,jQuery已經內置了$.isFunction函數幫助咱們完成這個檢測:
return this.each( function() { // Our plugin so far if ( $.isFunction( settings.complete ) ) { settings.complete.call( this ); } });
頁面中調用以下:
$('h2').helloWorld({ text : 'Salut, le monde!', color : '#005dff', fontStyle : 'italic', complete : function() { alert( 'Done!' ) } });
最終的效果,插件執行完畢後會觸發回調函數:
當你一遍又一遍的寫着大量重複的JavaScript代碼,自定義jQuery插件是一種很好擺脫這種泥沼的方式。經過自定義插件,你在保持本身代碼DRY(dont repeat yourself)的同時,也確保了全局名稱空間的獨立和純度。
若是你想調試上述示例代碼,能夠在個人 GitHub 獲取。