第8章 高效開發和使用外掛 (一)

mybwu_com發表於2013-12-28

jQuery 的流行在很大程度上歸功於其對外掛的支援。外掛也就是功能擴充套件的意思,jQuery 允許任何開發人員超越最初的庫函式建立並擴充套件 jQuery 函式。這種開放性框架設計思路催生了無數實用型的外掛,jQuery 幾乎能夠提供 Web 應用程式內所需的任何一種函式。

jQuery 的易擴充套件性吸引了越來越多的開發者和業餘愛好者去研究、設計和使用 jQuery 外掛。目前,全球有超過上千種不同應用需要的外掛。使用這些外掛能夠幫助開發人員提升開發速度,節約勞動成本。最權威的外掛可以訪問 jQuery 官方網站 (http://plugins.jquery.com) 獲取。本章將重點講解如何建立自己的 jQuery 外掛,並就網路上比較經典的幾個外掛設計原理和使用進行介紹。

8.1 建立 jQuery 外掛

網路上流傳著成百上千的第三方外掛,這些外掛雖然能夠增強我們的程式設計體驗,但是很難滿足所有設計需要,特別是個性化開發需求。如果自己編寫的程式碼可以重用,或者供其他使用者參考,很自然任何人都希望把這些程式碼進行封裝,打包為一個新外掛。這個實現過程並不困難,只要讀者認真閱讀本節內容即可輕鬆實現。

8.1.1 jQuery 外掛的型別

jQuery 外掛主要分為三種型別,說明如下。

1. jQuery 方法

這種型別的外掛是把一些常用或者重複使用的功能定義為函式,然後繫結到 jQuery 物件上,從而成為 jQuery 物件的一個擴充套件方法。

目前,大部分jQuery外掛都是這種型別的外掛,由於這種外掛是將物件方法封裝起來,在 jQuery 選擇器獲取 jQuery 物件的過程中進行操作,從而發揮 jQuery 強大的選擇器優勢。有很多 jQuery 內部方法,也是在 jQuery 指令碼內部通過這種形式插入到 jQuery 框架中的,如 parent() 、appendTo() 和 addClass() 等方法。

2.全域性函式

也可以把自定義的功能函式獨立附加到 jQuery 名稱空間下,從而作為 jQuery 作用域下的一個公共函式使用。例如,jQuery 的 ajax() 方法就是利用這種途徑內部定義的全域性函式。

==由於全域性函式沒有被繫結到 jQuery 物件上,故不能夠在選擇器獲取的 jQuery 物件上呼叫。需要通過 jQuery.fn() 或者 $.fn() 方式進行引用。==

3.選擇器

jQuery 提供了強大的選擇器,當然在個性化開發中,讀者也可能會感覺到這些選擇器不夠用,或者使用不是很方便。這個時候,我們就可以考慮自定義選擇器,以滿足特定環境下的選擇元素需要。

8.1.2 解析 jQuery 外掛機制

為了方便使用者建立外掛,jQuery 自定義了 jQuery.extend() 和 jQuery.fn.extend() 方法。其中 jQuery.extend() 方法能夠建立全域性函式或者選擇器,而 jQuery.fn.extend() 方法能夠建立 jQuery 物件方法。

例如,下面的示例將在 jQuery 名稱空間上建立兩個公共函式。

  1. <scripttype="text/javascript">
  2. jQuery.extend({//擴充套件jQuery的公共函式
  3. minValue:function(a,b){//比較兩個引數值,返回最小值
  4. returna<b?a:b;
  5. },
  6. maxValue:function(a,b){//比較兩個引數值,返回最大值
  7. returna<b?b:a;
  8. }
  9. });
  10. </script>
然後就可以在頁面中呼叫這兩個公共函式,示例程式碼如下所示。在下面這個示例中,當單擊按鈕後,瀏覽器會彈出提示對話方塊,要求輸入兩個值,然後提示兩個值的大小。

  1. <scripttype="text/javascript">
  2. jQuery.extend({//擴充套件jQuery的公共函式
  3. minValue:function(a,b){//比較兩個引數值,返回最小值
  4. returna<b?a:b;
  5. },
  6. maxValue:function(a,b){//比較兩個引數值,返回最大值
  7. returna<b?b:a;
  8. }
  9. });
  10. $(function(){
  11. $("input").click(function(){
  12. vara=prompt("請輸入一個數值?");
  13. varb=prompt("請再輸入一個數值?");
  14. varc=jQuery.minValue(a,b);
  15. vard=jQuery.maxValue(a,b);
  16. alert("你輸入的最大值是:"+d+"\n你輸入的最小值是:"+c);
  17. });
  18. });
  19. </script>
  20. </head>
  21. <body>
  22. <inputtype="button"value="jQuery外掛擴充套件測試"/>
  23. </body>

jQuery.extend() 和 jQuery.fn.extend() 方法都包含一個引數,該引數僅接受名/值對結構的物件,其中名錶示函式或方法名,而值表示函式體。關於如何建立 jQuery 外掛的問題,我們將在下面小節中進行詳細講解。

jQuery.extend() 方法除了可以建立外掛外,還可以用來擴充套件 jQuery 物件。例如,在下面的示例中,呼叫 jQuery.extend() 方法把物件 a 和 b 合併為一個新的物件,並返回合併物件將其賦值給變數 c 。

  1. <scripttype="text/javascript">
  2. vara={//物件直接量
  3. name:"zhu",
  4. pass:123
  5. };
  6. varb={//物件直接量
  7. name:"wang",
  8. pass:456,
  9. age:1
  10. };
  11. varc=jQuery.extend(a,b);//合併物件a和b
  12. $(function(){
  13. for(varnameinc){//遍歷物件c,顯示合併後的物件c的具體屬性和值
  14. $("div").html($("div").html()+"<br/>"+name+":"+c[name]);
  15. }
  16. });
  17. </script>
  18. </head>
  19. <body>
  20. <div></div>
  21. </body>

在實際開發中,常常使用 jQuery.extend() 方法為外掛方法傳遞系列選項結構的引數。

這樣當在呼叫該方法時,如果想傳遞新的引數值,就會覆蓋掉預設的引數選項值,或者向函式引數新增新的屬性和值;如果沒有傳遞引數,則保持並使用預設值。例如,在下面幾個函式呼叫中,分別傳入新值,或者新增新引數,或者保持預設值。

  1. <scripttype="text/javascript">
  2. functionfn(options){
  3. varoptions=jQuery.extend({//預設引數選項列表
  4. name1:value1,
  5. name2:value2,
  6. name3:value3,
  7. },options);//使用函式的引數覆蓋或合併到預設引數選項列表中
  8. //函式體
  9. }
  10. fn({name1:value2,name2:value3,name3:value1});//覆蓋新值
  11. fn({name4:value4,name5:value5});//新增新選項
  12. fn();//保持預設引數值
  13. </script>

jQuery.extend() 方法的物件合併機制,比傳統的逐個檢測引數不僅靈活且簡潔,使用命名引數新增新選項也不會影響已編寫的程式碼風格,讓程式碼變得更加直觀明白。

8.1.3 建立 jQuery 全域性函式

jQuery 內建的很多方法都是通過全域性函式實現的。所謂全域性函式,就是 jQuery 物件的方法,實際上就是位於 jQuery 名稱空間內部的函式。

有人把這類函式稱為實用工具函式,這些函式有一個共同特徵,就是不直接操作 DOM 元素,而是操作 JavaScript 的非元素物件,或者執行其他非物件的特定操作,如 jQuery 的 each() 函式和 noConflict() 函式。

回憶一下上一章講解過的 ajax() 方法,它就是一個典型的 jQuery 全域性函式,$.ajax() 所做的一切都可以通過呼叫名稱為 ajax() 的全域性函式來實現。但是,這種方式會帶來函式衝突問題,如果把函式放置在 jQuery 名稱空間內,就會降低這種衝突,只要在 jQuery 名稱空間內注意不要與 jQuery 其他方法衝突即可。

在上一節中曾經介紹了使用 jQuery.extend() 方法可以擴充套件 jQuery 物件的全域性函式。當然,我們也可以使用下面的方法快速定義 jQuery 全域性函式。例如,針對上一節示例,我們也可以按如下方法進行編寫。

  1. <scripttype="text/javascript">
  2. jQuery.minValue=function(a,b){
  3. returna<b?a:b;
  4. };
  5. jQuery.maxValue=function(a,b){
  6. returna<b?b:a;
  7. };
  8. </script>
也就是說,如果要向 jQuery 名稱空間上新增一個函式,只需要將這個新函式指定為 jQuery 物件的一個屬性即可。其中 jQuery 物件名也可以簡寫為 $ 。

考慮到 jQuery 的外掛越來越多,因此在使用時可能會遇到自己的外掛與第三方外掛名發生衝突的問題。為了避免這個問題,建議把屬於自己的外掛都封裝在一個物件中。例如,針對上面兩個建立的全域性函式,可以把它們封裝在自己的物件中,實現程式碼如下。

  1. <scripttype="text/javascript">
  2. jQuery.css8={
  3. minValue:function(a,b){
  4. returna<b?a:b;
  5. },
  6. maxValue:function(a,b){
  7. returna<b?b:b;
  8. }
  9. };
  10. </script>
儘管我們仍然可以把這些函式當成全域性函式來看待,但是從技術層面分析,它們現在都是 jQuery 全域性函式的方法,因此在呼叫這些函式時,請求方式也會發生變化,呼叫函式的程式碼如下。

  1. varc=jQuery.css8.minValue(a,b);
  2. vard=jQuery.css8.maxValue(a,b);
這樣就可以輕鬆避免與別的外掛發生衝突。注意,即使頁面中包含了 jQuery 框架檔案,但是考慮到安全性,不建議以一種簡寫的方式 (即使用 $ 代替 jQuery) 進行書寫,我們應該在編寫外掛中始終使用 jQuery 來呼叫 jQuery 方法。

8.1.4 使用 jQuery.fn 物件建立 jQuery 物件方法

除了全域性函式外,jQuery 中的大多數功能都是通過 jQuery 物件的方法提供的,這些物件方法對於 DOM 操作來說非常方便,這也是很多使用者喜歡並選用 jQuery 框架的原因。

建立全域性函式只需要通過為 jQuery 物件新增屬性即可,而建立 jQuery 物件方法也可以通過為 jQuery.fn 物件新增屬性來實現。實際上 jQuery.fn 物件就是 jQuery.prototype 原型物件的別名,使用別名更方便引用。例如,下面這個函式就是一個簡單的 jQuery 物件方法,當呼叫該方法時,將會彈出一個提示對話方塊。

  1. <scripttype="text/javascript">
  2. jQuery.fn.test=function(){
  3. alert('這是jQuery物件方法!');
  4. };
  5. </script>
然後,就可以在任何 jQuery 物件中呼叫該方法。在下面的應用示例中,如果單擊頁面中的 "jQuery外掛擴充套件測試" 按鈕,即可彈出一個提示對話方塊,提示 "這是jQuery物件方法!"。

  1. <scripttype="text/javascript">
  2. jQuery.fn.test=function(){
  3. alert('這是jQuery物件方法!');
  4. };
  5. $(function(){
  6. $("input").click(function(){//繫結click事件
  7. $(this).test();//在當前的jQuery物件上呼叫test()方法
  8. });
  9. });
  10. </script>
  11. </head>
  12. <body>
  13. <inputtype="button"value="jQuery外掛擴充套件測試"/>
  14. </body>

由於這裡並沒有在任何地方匹配 DOM 節點,所以編寫全域性函式也是可以的。但是,在使用 jQuery 物件方法時,函式體內的 this 關鍵字總是引用當前 jQuery 物件,因此我們可以對上面的方法進行重寫,實現動態提示資訊。程式碼如下。

  1. <scripttype="text/javascript">
  2. jQuery.fn.test=function(){
  3. alert(this[0].nodeName);//提示當前jQuery物件的DOM節點名稱
  4. };
  5. $(function(){
  6. $("input").click(function(){//繫結click事件
  7. $(this).test();//在當前的jQuery物件上呼叫test()方法
  8. });
  9. });
  10. </script>
  11. </head>
  12. <body>
  13. <inputtype="button"value="jQuery外掛擴充套件測試"/>
  14. </body>

這樣,當單擊按鈕時,就會彈出當前元素的節點名稱。

在上面的示例中,可以看到由於 jQuery 選擇器返回的是一個陣列型別的 DOM 節點集合,this 指標就指向當前這個集合,故要顯示當前元素的節點名稱,就必須在 this 指標後面指定當前元素的序號。

試想,如果 jQuery 選擇器匹配多個元素,我們該如何準確指定當前元素物件呢?

要解決這個問題,我們不妨在當前 jQuery 物件方法的環境中呼叫 each() 方法,通過隱式迭代的方式,讓 this 指標依次引用每一個匹配的 DOM 元素物件。這樣也能夠保持外掛與 jQuery 內建方法保持一致。例如,針對上面的示例做進一步的修改。

  1. jQuery.fn.test=function(){
  2. this.each(function(){//遍歷所有匹配的元素,此處的this表示物件集合,即jQuery物件
  3. alert(this.nodeName);//顯示當前元素的節點名稱,此處的this表示元素物件
  4. });
  5. };
然後,在呼叫該方法時,就不用擔心 jQuery 選擇器所匹配的元素有多少了。例如,在下面的示例中,當單擊不同型別的元素,會提示當前元素的節點名稱。

  1. <scripttype="text/javascript">
  2. jQuery.fn.test=function(){
  3. this.each(function(){//遍歷所有匹配的元素,此處的this表示物件集合,即jQuery物件
  4. alert(this.nodeName);//顯示當前元素的節點名稱,此處的this表示元素物件
  5. });
  6. };
  7. $(function(){
  8. $("body*").click(function(){//選擇body元素下所有元素
  9. $(this).test();//為當前元素呼叫test()方法,提示當前DOM元素物件的節點名稱
  10. });
  11. });
  12. </script>
  13. </head>
  14. <body>
  15. <inputtype="button"value="jQuery外掛擴充套件測試"/>
  16. <div>div元素</div>
  17. <p>p元素</p>
  18. <span>span元素</span>
  19. </body>
這樣就可以實現根據前面選擇器所匹配元素的不同,令所定義的 test() 方法給出不同的提示資訊。

用慣 jQuery 的使用者可能習慣於連寫行為,也就是說在呼叫一個方法之後,緊跟著呼叫另一個方法,如此連寫不斷,形成一個珍珠鏈,而且編寫靈活、方便,也符號人的思維習慣。例如

$(this).test().hide().height();

要實現類似的行為連寫功能,就應該在每個外掛方法中返回一個 jQuery 物件,除非方法需要明確返回值。返回的 jQuery 物件通常就是 this 所引用的物件。如果使用 each() 方法迭代 this ,則可以直接返回迭代的結果。例如,針對上面的示例做如下進一步的修改。

  1. jQuery.fn.test=function(){
  2. returnthis.each(function(){//返回迭代的jQuery物件
  3. alert(this.nodeName);
  4. });
  5. };
然後,我們就可以在應用示例中連寫行為了。例如,在下面的示例中,先彈出提示節點名稱的資訊,然後使用當前節點名稱改寫當前元素內包含的資訊,最後再慢慢隱藏該元素。

  1. <scripttype="text/javascript">
  2. jQuery.fn.test=function(){
  3. returnthis.each(function(){//返回迭代的jQuery物件
  4. alert(this.nodeName);
  5. });
  6. };
  7. $(function(){
  8. $("body*").click(function(){//選擇body元素下所有元素
  9. $(this).test().html(this.nodeName).hide(4000);//行為連寫
  10. });
  11. });
  12. </script>
  13. </head>
  14. <body>
  15. <inputtype="button"value="jQuery外掛擴充套件測試"/>
  16. <div>div元素</div>
  17. <p>p元素</p>
  18. <span>span元素</span>
  19. </body>

8.1.5 使用 extend() 方法建立 jQuery 物件方法

jQuery.extend() 方法能夠建立全域性函式,而 jQuery.fn.extend() 方法可以建立 jQuery 物件方法。如果讀者明白了上一節使用 jQuery.fn 物件屬性的方法建立 jQuery 物件方法,那麼使用 extend() 方法建立 jQuery 物件就比較容易理解了。

例如,針對上節中介紹的示例,我們可以呼叫 jQuery.fn.extend() 方法來建立 jQuery 物件方法。具體程式碼如下。

  1. jQuery.fn.extend({
  2. test:function(){
  3. returnthis.each(function(){
  4. alert(this.nodeName);
  5. });
  6. }
  7. });
jQuery.fn.extend()方法僅包含一個引數,該引數是一個物件直接量,是以名/值對形式組成的多個屬性,名稱表示方法名稱,而值表示函式體。因此,在這個物件直接量中可以附加多個屬性,為 jQuery 物件同時定義多個方法。

針對上面定義的 test() 方法,同樣可以在 jQuery 選擇器中直接呼叫。

  1. <scripttype="text/javascript">
  2. jQuery.fn.extend({
  3. test:function(){
  4. returnthis.each(function(){
  5. alert(this.nodeName);
  6. });
  7. }
  8. });
  9. $(function(){
  10. $("body*").click(function(){//選擇body元素下所有元素
  11. $(this).test().html(this.nodeName).hide(4000);//行為連寫
  12. });
  13. });
  14. </script>
  15. </head>
  16. <body>
  17. <inputtype="button"value="jQuery外掛擴充套件測試"/>
  18. <div>div元素</div>
  19. <p>p元素</p>
  20. <span>span元素</span>
  21. </body>

相關文章