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

mybwu_com發表於2013-12-28

8.1.8 封裝 jQuery 外掛

上面幾節就 jQuery 外掛的建立方法進行了詳細講解,一般對外發布的自定義外掛都應該進行封裝,封裝的外掛還應該符合規範,只有這樣所建立的外掛才具有推廣價值,並得到其他使用者的喜愛。

封裝 jQuery 外掛的第一步是定義一個獨立域,程式碼如下所示。

  1. <scripttype="text/javascript">
  2. (function($){
  3. //自定義外掛程式碼
  4. })(jQuery);//封裝外掛
  5. </script>

確定建立外掛型別,選擇建立方式。例如,建立一個設定元素字型顏色的外掛,則應該建立 jQuery 物件方法。考慮到 jQuery 提供了外掛擴充套件方法 extend() ,呼叫該方法定義外掛會更為規範。程式碼如下。

  1. (function($){
  2. $.extend($.fn,{//jQuery物件方法擴充套件
  3. //函式列表
  4. });
  5. })(jQuery);//封裝外掛
一般外掛都會接受引數,用來控制外掛的行為,根據 jQuery 設計習慣,我們可以把所有引數以列表形式封裝在選項物件中進行傳遞。例如,對於設定元素字型顏色的外掛,應該允許使用者設定字型顏色,同時還應該考慮如果使用者沒有設定顏色,則應確保使用預設色進行設定。實現程式碼如下所示。

  1. (function($){
  2. $.extend($.fn,{//jQuery物件方法擴充套件
  3. color:function(options){//自定義外掛名稱
  4. varoptions=$.extend({//引數選項物件處理
  5. bcolor:"white",//背景色預設值
  6. fcolor:"black"//前景色預設值
  7. },options);
  8. //函式體
  9. }
  10. });
  11. })(jQuery);//封裝外掛
最後,設計外掛自定義功能程式碼,如下所示。

  1. (function($){
  2. $.extend($.fn,{//jQuery物件方法擴充套件
  3. color:function(options){//自定義外掛名稱
  4. varoptions=$.extend({//引數選項物件處理
  5. bcolor:"white",//背景色預設值
  6. fcolor:"black"//前景色預設值
  7. },options);
  8. returnthis.each(function(){//返回匹配的jQuery物件
  9. $(this).css("color",options.fcolor);//遍歷設定每個DOM元素的字型顏色
  10. $(this).css("backgroundColor",options.bcolor);//遍歷設定每個DOM元素的背景色
  11. });
  12. }
  13. });
  14. })(jQuery);//封裝外掛
完成外掛封裝之後,我們不妨來測試一下自定義的 color() 方法。程式碼如下。

  1. <scripttype="text/javascript">
  2. (function($){
  3. $.extend($.fn,{
  4. color:function(options){//自定義外掛名稱
  5. varoptions=$.extend({//引數選項物件處理
  6. bcolor:"white",//背景色預設值
  7. fcolor:"black"//前景色預設值
  8. },options);
  9. returnthis.each(function(){//返回匹配的jQuery物件
  10. $(this).css("color",options.fcolor);//遍歷設定每個DOM元素的字型顏色
  11. $(this).css("backgroundColor",options.bcolor);//遍歷設定每個DOM元素的背景顏色
  12. });
  13. }
  14. });
  15. })(jQuery);//封裝外掛
  16. $(function(){//頁面初始化
  17. $("h1").color({//設定標題的前景色和背景色
  18. bcolor:"#eea",
  19. fcolor:"red"
  20. });
  21. });
  22. </script>
  23. </head>
  24. <body>
  25. <h1>標題文字</h1>

8.1.9 優化 jQuery 外掛 -- 開放公共引數

優秀的 jQuery 外掛,應該以開放性的姿態滿足不同個性化的設計要求,同時還應該做好封閉性,避免外界有意或無意的破壞。

首先,可以考慮開發外掛的預設設定,這對於外掛使用者來說,會更容易使用較少的程式碼覆蓋和修改外掛。

繼續以上面的程式碼為例進行說明,把其中的引數預設值作為 $.fn.color 物件的屬性單獨進行設計,然後藉助 jQuery.extend() 方法覆蓋原來引數選項即可

  1. <scripttype="text/javascript">
  2. (function($){
  3. $.extend($.fn,{
  4. color:function(options){
  5. varoptions=$.extend({},$.fn.color.defaults,options);
  6. returnthis.each(function(){//返回匹配的jQuery物件
  7. $(this).css("color",options.fcolor);//遍歷設定每個DOM元素的字型顏色
  8. $(this).css("backgroundColor",options.bcolor);//遍歷設定每個DOM元素的背景顏色
  9. });
  10. }
  11. });
  12. $.fn.color.defaults={//獨立設定$.fn.color物件的預設引數值
  13. bcolor:"white",
  14. fcolor:"black"
  15. };
  16. })(jQuery);//封裝外掛
  17. $(function(){//頁面初始化
  18. $("h1").color({//設定標題的前景色和背景色
  19. bcolor:"#eea",
  20. fcolor:"red"
  21. });
  22. });
  23. </script>
在 color() 函式中,jQuery.extend() 方法能夠使用引數 options 覆蓋預設的 defaults 屬性值,如果沒有設定 options 引數值,則使用 defaults 屬性值。同時,由於 defaults 屬性是單獨定義的,故我們可以在頁面中預設前景色和背景色,然後就可以多次呼叫 color() 方法,示例程式碼如下。通過這種開發外掛預設引數的做法,使用者不再需要重複定義引數,這樣就可以節省開發時間。

  1. <scripttype="text/javascript">
  2. (function($){
  3. $.extend($.fn,{
  4. color:function(options){
  5. varoptions=$.extend({},$.fn.color.defaults,options);
  6. returnthis.each(function(){//返回匹配的jQuery物件
  7. $(this).css("color",options.fcolor);//遍歷設定每個DOM元素的字型顏色
  8. $(this).css("backgroundColor",options.bcolor);//遍歷設定每個DOM元素的背景顏色
  9. });
  10. }
  11. });
  12. $.fn.color.defaults={//獨立設定$.fn.color物件的預設引數值
  13. bcolor:"white",
  14. fcolor:"black"
  15. };
  16. })(jQuery);//封裝外掛
  17. $(function(){//頁面初始化
  18. $.fn.color.defaults={//預設預設的前景色和背景色
  19. bcolor:"#eea",
  20. fcolor:"red"
  21. };
  22. $("h1").color();
  23. $("p").color({bcolor:"#fff"});//為段落文字設定預設色,同時覆蓋背景色為白色
  24. $("div").color();//為盒子設定預設色
  25. });
  26. </script>
  27. </head>
  28. <body>
  29. <h1>標題文字</h1>
  30. <p>段落文字</p>
  31. <div>盒子</div>
  32. </body>

8.1.10 優化jQuery外掛 -- 開放部分功能

用過 Cycle 外掛外掛的讀者可能會知道,它是一個滑動顯示外掛,支援很多內部變換功能,如滾動、滑動和漸變消失等。實際上,在封裝外掛時,我們無法把所有功能都封裝進去,也沒有辦法定義滑動變化上每一種型別的變化效果。但是 Cycle 外掛通過開放部分功能,允許使用者重寫 transitions 物件,這樣就可以新增自定義變化效果,從而使該外掛滿足不同使用者的不同需求。

Cycle 外掛是這樣開放部分功能的,程式碼如下。

  1. $.fn.cycle.transitions={
  2. //擴充套件方法
  3. };
這個技巧就可以允許其他使用者定義和傳遞引數到 Cycle 外掛內部。

例如,繼續以上一節的示例為基礎,我們為其新增一個格式化的擴充套件功能,這樣使用者在設定顏色的同時,還可以根據需要適當進行格式化功能設計,如加粗、斜體、放大等功能操作。擴充套件的 color() 外掛程式碼如下所示。

  1. (function($){
  2. $.extend($.fn,{
  3. color:function(options){
  4. varoptions=$.extend({},$.fn.color.defaults,options);//覆蓋原來引數
  5. returnthis.each(function(){
  6. $(this).css("color",options.fcolor);
  7. $(this).css("backgroundColor",options.bcolor);
  8. var_html=$(this).html();//獲取當前元素包含的HTML字串
  9. _html=$.fn.color.format(_html);//呼叫格式化功能函式對其進行格式化
  10. $(this).html(_html);//使用格式化的HTML字串重寫當前元素內容
  11. });
  12. }
  13. });
  14. $.fn.color.defaults={//獨立設定$.fn.color物件的預設引數值
  15. bcolor:"white",
  16. fcolor:"black"
  17. };
  18. $.fn.color.format=function(str){//開放的功能函式
  19. returnstr;
  20. }
  21. })(jQuery);//封裝外掛
在上面的示例中,通過開發的方式定義了一個 format() 功能函式,在這個功能函式中預設沒有進行格式化設定,然後在 color() 函式體內利用這個開放性功能函式格式化當前元素內的 HTML 字串。

例如,下面的示例呼叫了 color() 外掛,同時在呼叫時分別擴充套件了它的格式化功能。

  1. <scripttype="text/javascript">
  2. (function($){
  3. $.extend($.fn,{
  4. color:function(options){
  5. varoptions=$.extend({},$.fn.color.defaults,options);//覆蓋原來引數
  6. returnthis.each(function(){
  7. $(this).css("color",options.fcolor);
  8. $(this).css("backgroundColor",options.bcolor);
  9. var_html=$(this).html();//獲取當前元素包含的HTML字串
  10. _html=$.fn.color.format(_html);//呼叫格式化功能函式對其進行格式化
  11. $(this).html(_html);//使用格式化的HTML字串重寫當前元素內容
  12. });
  13. }
  14. });
  15. $.fn.color.defaults={//獨立設定$.fn.color物件的預設引數值
  16. bcolor:"white",
  17. fcolor:"black"
  18. };
  19. $.fn.color.format=function(str){//開放的功能函式
  20. returnstr;
  21. }
  22. })(jQuery);//封裝外掛
  23. $(function(){//頁面初始化
  24. $.fn.color.defaults={//預設預設的前景色和背景色
  25. bcolor:"#eea",
  26. fcolor:"red"
  27. };
  28. $.fn.color.format=function(str){//擴充套件color()外掛的功能,使內部文字加粗顯示
  29. return"<strong>"+str+"</strong>";
  30. };
  31. $("h1").color();
  32. $("p").color({bcolor:"#fff"});//為段落文字設定預設色,同時覆蓋背景色為白色
  33. $.fn.color.format=function(str){//擴充套件color()外掛的功能,使內部文字放大顯示
  34. return"<spanstyle='font-size:30px;'>"+str+"</span>";
  35. };
  36. $("div").color();//為盒子設定預設色
  37. });
  38. </script>
  39. </head>
  40. <body>
  41. <h1>標題文字</h1>
  42. <p>段落文字</p>
  43. <div>盒子</div>
  44. </body>
上述技巧讓使用者能夠傳遞自己的功能設定,以覆蓋外掛預設的功能,從而方便了其他使用者以當前外掛為基礎進一步去擴寫外掛。

8.1.11 優化 jQuery 外掛 -- 保留外掛隱私

優秀的外掛,不僅僅要追求開放性,還應該留意外掛的隱私性,對於不該暴露的部分,如果不注意保護,很容易被外界入侵,從而破壞外掛的功能。因此,在設計外掛時必須考慮外掛實現中不應該暴露的部分。一旦被暴露,就需要銘記任何對於引數或者語義的改動也許會破壞向後的相容性。如果不能確定不應該暴露的特定函式,那麼就必須考慮如何進行保護的問題。

若外掛包含很多函式,在設計時我們希望這麼多函式不攪亂名稱空間,也不會被完全暴露,惟一的方法就是使用閉包。為了建立閉包,可以將整個外掛封裝在一個函式中。

繼續以上節示例進行講解,為了驗證使用者在呼叫 color() 方法時所傳遞的引數是否合法,我們不妨在外掛中定義一個引數驗證函式,但是該驗證函式是不允許外界侵入或者訪問的,此時我們可以藉助閉包把它隱藏起來,只允許在外掛內部進行訪問。實現的程式碼如下。

  1. <scripttype="text/javascript">
  2. (function($){
  3. $.extend($.fn,{
  4. color:function(options){
  5. if(!filter(options))//呼叫隱私方法驗證引數,不合法則返回
  6. returnthis;
  7. varoptions=$.extend({},$.fn.color.defaults,options);//覆蓋原來引數
  8. returnthis.each(function(){
  9. $(this).css("color",options.fcolor);
  10. $(this).css("backgroundColor",options.bcolor);
  11. var_html=$(this).html();//獲取當前元素包含的HTML字串
  12. _html=$.fn.color.format(_html);//呼叫格式化功能函式對其進行格式化
  13. $(this).html(_html);//使用格式化的HTML字串重寫當前元素內容
  14. });
  15. }
  16. });
  17. $.fn.color.defaults={//獨立設定$.fn.color物件的預設引數值
  18. bcolor:"white",
  19. fcolor:"black"
  20. };
  21. $.fn.color.format=function(str){//開放的功能函式
  22. returnstr;
  23. }
  24. functionfilter(options){//定義隱私函式,外界無法訪問
  25. //如果引數不存在,或者存在且為物件,則返回true,否則返回false
  26. return!options||(options&&typeofoptions==="object")?true:false;
  27. }
  28. })(jQuery);//封裝外掛
  29. $(function(){//頁面初始化
  30. $.fn.color.defaults={//預設預設的前景色和背景色
  31. bcolor:"#eea",
  32. fcolor:"red"
  33. };
  34. $.fn.color.format=function(str){//擴充套件color()外掛的功能,使內部文字加粗顯示
  35. return"<strong>"+str+"</strong>";
  36. };
  37. $("h1").color();
  38. $("p").color({bcolor:"#fff"});//為段落文字設定預設色,同時覆蓋背景色為白色
  39. $.fn.color.format=function(str){//擴充套件color()外掛的功能,使內部文字放大顯示
  40. return"<spanstyle='font-size:30px;'>"+str+"</span>";
  41. };
  42. $("div").color();//為盒子設定預設色
  43. });
  44. </script>
  45. </head>
  46. <body>
  47. <h1>標題文字</h1>
  48. <p>段落文字</p>
  49. <div>盒子</div>
  50. </body>
這樣對於下面的非法引數設定,則會忽略該方法的呼叫,但是不會丟擲異常。

  1. $(function(){
  2. $("p").color("#fff");
  3. });

8.1.12 優化 jQuery 外掛 -- 非破壞性操作

在特定情況下,jQuery 物件方法可能會修改 jQuery 物件匹配的 DOM 元素,這時就有可能破壞方法返回值的一致性。為了遵循 jQuery 框架的核心設計理念,我們應該時刻警惕任何修改 jQuery 物件的操作。

例如,定義一個 jQuery 物件方法 parent() ,用來獲取 jQuery 匹配的所有 DOM 元素的父元素。實現程式碼如下。

  1. <scripttype="text/javascript">
  2. (function($){
  3. $.extend($.fn,{
  4. parent:function(){//擴充套件jQuery物件方法,獲取所有匹配元素的父元素
  5. vararr=[];
  6. $.each(this,function(index,value){//遍歷匹配的DOM元素
  7. arr.push(value.parentNode);//把匹配元素的父元素推入臨時陣列
  8. });
  9. arr=$.unique(arr);//在臨時陣列中過濾重複的元素
  10. returnthis.setArray(arr);//把變數arr打包為陣列型別返回
  11. }
  12. });
  13. })(jQuery);//封裝外掛
  14. </script>
在上面的 jQuery 物件方法中,通過遍歷所有的匹配元素,獲取每個 DOM 元素的父元素,並把這些父元素儲存到一個臨時陣列中,通過過濾、打包再返回。

下面我們就用這個新方法為所有 p 元素的父元素新增一個邊框,示例程式碼如下所示。

  1. <scripttype="text/javascript">
  2. (function($){
  3. $.extend($.fn,{
  4. parent:function(){//擴充套件jQuery物件方法,獲取所有匹配元素的父元素
  5. vararr=[];
  6. $.each(this,function(index,value){//遍歷匹配的DOM元素
  7. arr.push(value.parentNode);//把匹配元素的父元素推入臨時陣列
  8. });
  9. arr=$.unique(arr);//在臨時陣列中過濾重複的元素
  10. returnthis.setArray(arr);//把變數arr打包為陣列型別返回
  11. }
  12. });
  13. })(jQuery);//封裝外掛
  14. $(function(){
  15. var$p=$("p");//獲取所有p元素,並儲存到變數$p中
  16. $p.parent().css("border","solid1pxred");//呼叫parent()方法獲取p元素的父元素,並設定它們的邊框樣式
  17. });
  18. </script>
  19. </head>
  20. <body>
  21. <divstyle="width:400px;height:200px;">大盒子
  22. <p>段落文字1</p>
  23. <divstyle="width:200px;height:100px;">小盒子
  24. <p>段落文字2</p>
  25. </div>
  26. </div>
  27. </body>
如果在設定了父元素的邊框後,我們希望把 jQuery 物件匹配的所有元素都隱藏起來,則可以新增下面的程式碼,則在瀏覽器中預覽就會發現 div 元素也被隱藏起來了。

  1. $(function(){
  2. var$p=$("p");//獲取所有p元素,並儲存到變數$p中
  3. $p.parent().css("border","solid1pxred");//呼叫parent()方法獲取p元素的父元素,並設定它們的邊框樣式
  4. $p.hide();//隱藏所有p元素,即當前jQuery物件
  5. });
也就是說,在上面程式碼中 $p 變數已經被修改,它不再指向當前 jQuery 物件,而是指向 jQuery 物件匹配元素的父元素,因此在為 $p 呼叫 hide() 方法時,就會隱藏 div 元素,而不是 p 元素。

上面示例僅僅是破壞性操作的一種表現,如果要避免此類隱性修改 jQuery 物件的行為,建議採用非破壞性操作。例如,在本例中我們可以使用 pushStack() 方法建立一個新的 jQuery 物件,而不是修改 this 所引用的 jQuery 物件,這樣可以避免破壞性操作行為,同時 pushStack() 方法還允許呼叫 end() 方法操作新建立的 jQuery 物件方法。把上面的示例的 jQuery 物件方法進行優化,程式碼如下所示。

  1. <scripttype="text/javascript">
  2. (function($){
  3. $.extend($.fn,{
  4. parent:function(options){//擴充套件jQuery物件方法,獲取所有匹配元素的父元素
  5. vararr=[];
  6. $.each(this,function(index,value){//遍歷匹配的DOM元素
  7. arr.push(value.parentNode);//把匹配元素的父元素推入臨時陣列
  8. });
  9. arr=$.unique(arr);//在臨時陣列中過濾重複的元素
  10. returnthis.pushStack(arr);//返回新建立的jQuery物件,而不是修改後的當前jQuery物件
  11. }
  12. });
  13. })(jQuery);//封裝外掛
  14. $(function(){
  15. var$p=$("p");//獲取所有p元素,並儲存到變數$p中
  16. $p.parent().css("border","solid1pxred");//呼叫parent()方法獲取p元素的父元素,並設定它們的邊框樣式
  17. $p.hide();//隱藏所有p元素,即當前jQuery物件
  18. });
  19. </script>
  20. </head>
  21. <body>
  22. <divstyle="width:400px;height:200px;">大盒子
  23. <p>段落文字1</p>
  24. <divstyle="width:200px;height:100px;">小盒子
  25. <p>段落文字2</p>
  26. </div>
  27. </div>
  28. </body>
這時,如果繼續執行上面的演示例項操作,則可以看到 div 元素邊框樣式被定義為紅色實現了,同時也隱藏了其包含的 p 元素。

針對上面的程式碼,我們就可以採用連續行為進行編寫了,程式碼如下所示。

  1. $(function(){
  2. var$p=$("p");//獲取所有p元素,並儲存到變數$p中
  3. $p.parent().css("border","solid1pxred").end().hide();
  4. });
其中 end() 方法能夠恢復被破壞的 jQuery 物件,也就是說 parent() 方法返回的是當前元素的父元素的集合,現在呼叫 end() 方法之後,又恢復到最初的當前元素集合,此時可以繼續呼叫方法作用於原來的 jQuery 物件上了。

相關文章