jQuery外掛編寫及鏈式程式設計模型小結

雲霏霏發表於2015-04-08

   JQuery極大的提高了我們編寫JavaScript的效率,讓我們可以愉快的編寫程式碼,做出各種特效。大多數情況下,我們都是使用別人開發的JQuery外掛,今天我們就來看看如何把我們常用的功能做出JQuery外掛,然後像使用jQuery那樣來操作DOM.

 一、jQuery外掛開發快速上手

1、jQuery外掛模板

關於jQuery外掛的編寫,我們可以通過為jQuery.fn增加一個新的函式來編寫jQuery外掛。屬性的名字就是你的外掛的名字,其模板如下:

(function($){
   $.fn.myJQPlugin = function(){
      //TODO:add your code
   }
})(jQuery);

其中myJQPlugin 就是你外掛的名字,Function裡面的程式碼就是你外掛的功能實現程式碼。

 

2、與DOM互動

給外掛起好名字後,下面就可以編寫我們的程式碼了,但是編寫之前,必須要說一說上下文。在外掛內部的範圍中,this關鍵字指向的是jQuery物件。人們很容易誤解這一點,因為在正常使用jQuery的時候,this通常指向的是一個DOM元素。不瞭解這一點,會經常使用$又包裝了一次。

(function( $ ){  
$.fn.myJQPlugin = function() {  
      // 沒有必要使用$(this)  
      // $(this) 跟 $($('#element'))是一樣的   
      this.html("Hello,world");
      this.click(function(){
         this.hide(); //注意這裡的this不再指向jQuery元素,這裡的this指向當前這個function物件
      });
   };  
})( jQuery ); 

這裡又要提到this的指向問題,比如我們想實現一個功能,點選DOM元素,隱藏當前元素,雖然說this指向的是jQuery物件,但是在click中,this的指向發生了變化,指向了它所在的function.所以我們在click方法裡面訪問當前元素,就要通過變數了,實現方法如下:

(function( $ ){  
$.fn.myJQPlugin = function() {  
      // 沒有必要使用$(this)  
      // $(this) 跟 $($('#element'))是一樣的   
      this.html("Hello,world");
      var $this = $(this);
      this.click(function(){
         $this.hide(); //注意這裡的this不再指向jQuery元素,這裡的this指向當前這個function物件
      });
   };  
})( jQuery );  

我們宣告$this變數來儲存this物件,這樣我們需要使用當前元素時,直接使用$this就可以了。下面我們通過一個完整的例項來測試一下:

其中html頁面的程式碼如下:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <script src="jquery.js" type="text/javascript"></script>
    <script src="1.js" type="text/javascript"></script>
</head>
<body>
<div id="container" style="width:800px;height:200px; border:2px #000 solid;padding:20px;font-size:20px;">Hello,world</div>
</body>
<script type="text/javascript">
  $('#container').myJQPlugin();  
</script>
</html>

jQuery外掛的js程式碼如下:

(function($){
   $.fn.myJQPlugin = function(){
      this.css("color","red"); //字型顏色為紅色
      this.hide();  
      this.slideDown(200);   //先隱藏,然後通過slideDown顯示出來
      var $this = $(this);
      this.click(function(){
      $this.html("Thanks,good bye!"); //顯示資訊,然後淡出
      $this.fadeOut(2000);
      });
   }
})(jQuery);

這個外掛的功能就是首先讓元素下拉顯示,然後點選元素時顯示再見資訊,然後經過2s後淡出。這裡大家可以試試在click事件裡面使用this會怎麼樣。

 

 二、jQuery的鏈式操作

1、為什麼要用鏈式操作?

實際上鍊式操作僅僅是通過物件上的方法最後加上return this. 把物件再返回回來,物件當然可以繼續呼叫方法啦,所以就可以鏈式操作了。那麼,簡單實現一個:

//定義一個JS類
function Demo() {
 
}
//擴充套件它的prototype
Demo.prototype ={
    setName:function (name) {
        this.name = name;
        return this;
    },
    getName:function () {
        return this.name;
    },
    setAge:function (age) {
        this.age = age;
        return this;
    }
};
 
////工廠函式
function D() {
    return new Demo();
}
//去實現可鏈式的呼叫
D().setName("CJ").setAge(18).setName();

 

一般的解釋:

節省程式碼量,程式碼看起來更優雅。例如如果沒有鏈式,那麼你可能需要這樣寫程式碼:

document.getElementById("ele").dosomething(); 
document.getElementById("ele").dootherthing(); 

這個程式碼中呼叫了兩次document.getElementById來獲取DOM樹的元素,這樣消耗比較大,而且要寫兩行,而鏈式只要寫一行,節省了程式碼……

但我們也可以用快取元素啊。比如:

var ele = document.getElementById("ele"); 
ele.dosomething(); 
ele.dootherthing(); 

而且兩行並沒有比一行多多少程式碼,甚至相應的封裝反而使得程式碼更多了。
最糟糕的是所有物件的方法返回的都是物件本身,也就是說沒有返回值,這不一定在任何環境下都適合。

 

2、那麼到底為什麼要用鏈式操作呢?

為了更好的非同步體驗Javascript是無阻塞語言,所以他不是沒阻塞,而是不能阻塞,所以他需要通過事件來驅動,非同步來完成一些本需要阻塞程式的操作。 

但是非同步程式設計是一種令人瘋狂的東西……執行時候是分離的倒不要緊,但是編寫程式碼時候也是分離的就……

常見的非同步程式設計模型有哪些呢? 

(1)回撥函式 :

所謂的回撥函式,意指先在系統的某個地方對函式進行註冊,讓系統知道這個函式的存在,然後在以後,當某個事件發生時,再呼叫這個函式對事件進行響應。 

function fun(num, callback){ 
   if(num < 0) { 
      alert("分數不能為負,輸入錯誤!"); 
   }else if(num == 0){ 
      alert("該學生可能未參加考試!"); 
   }else { 
      alert("呼叫高層函式處理!"); 
      setTimeout(function(){callback();}, 1000); 
   } 
} 

這裡callback則是回撥函式。可以發現只有當num為非負數時候callback才會呼叫。
但是問題,如果我們不看函式內部,我們並不知道callback會幾時呼叫,在什麼情況下呼叫,程式碼間產生了一定耦合,流程上也會產生一定的混亂。

雖然回撥函式是一種簡單而易於部署的實現非同步的方法,但從程式設計體驗來說它卻不夠好。

 

(2)鏈式非同步 :

個人覺得鏈式操作最值得稱讚的還是其解決了非同步程式設計模型的執行流程不清晰的問題。jQuery中$(document).ready就非常好的闡釋了這一理念。DOMContentLoaded是一個事件,在DOM並未載入前,jQuery的大部分操作都不會奏效,但jQuery的設計者並沒有把他當成事件一樣來處理,而是轉成一種“選其物件,對其操作”的思路。$選擇了document物件,ready是其方法進行操作。這樣子流程問題就非常清晰了,在鏈條越後位置的方法就越後執行。 

(function(){ 
   var isReady=false; //判斷onDOMReady方法是否已經被執行過 
   var readyList= [];//把需要執行的方法先暫存在這個陣列裡 
   var timer;//定時器控制程式碼 
   ready=function(fn) { 
      if (isReady ) 
         fn.call( document); 
      else 
         readyList.push( function() { return fn.call(this);}); 
      return this; 
   } 
   var onDOMReady=function(){ 
      for(var i=0;i<readyList.length;i++){ 
         readyList[i].apply(document); 
      } 
      readyList = null; 
   } 
   var bindReady = function(evt){ 
      if(isReady) return; 
         isReady=true; 
         onDOMReady.call(window); 
         if(document.removeEventListener){ 
         document.removeEventListener("DOMContentLoaded", bindReady, false); 
      } else if(document.attachEvent){ 
         document.detachEvent("onreadystatechange", bindReady); 
         if(window == window.top){ 
            clearInterval(timer); 
            timer = null; 
         } 
      } 
   }; 
   if(document.addEventListener){ 
      document.addEventListener("DOMContentLoaded", bindReady, false); 
   }else if(document.attachEvent){ 
         document.attachEvent("onreadystatechange", function(){ 
         if((/loaded|complete/).test(document.readyState)) 
            bindReady(); 
         }); 
         if(window == window.top){ 
            timer = setInterval(function(){ 
            try{ 
               isReady||document.documentElement.doScroll('left');//在IE下用能否執行doScroll判斷dom是否載入完畢
            }
            catch(e){ 
               return; 
            } 
            bindReady(); 
         },5); 
      } 
   } 
})(); 

上面的程式碼不能用$(document).ready,而應該是window.ready。 

 

(3)Promise :

CommonJS中的非同步程式設計模型也延續了這一想法,每一個非同步任務返回一個Promise物件,該物件有一個then方法,允許指定回撥函式。 

所以我們可以這樣寫:
f1().then(f2).then(f3);
這種方法我們無需太過關注實現,也不太需要理解非同步,只要懂得通過函式選物件,通過then進行操作,就能進行非同步程式設計。

 

 三、維護鏈式開發的特性

   在jQuery中,一個外掛緊緊是修改收集到的元素,然後返回這個元素讓鏈條上的下一個使用。這是jQuery設計的精美之處,也是jQuery如此流行的原因之一。為了保證可鏈式,你必須返回this。如下程式碼:

(function( $ ){  
  $.fn.resize = function( type, value ) {    
   return this.each(function() {  
      var $this = $(this);  
      if (!type || type == 'width' ) {  
         $this.width(value);  
      }  
      if ( !type || type == 'height' ) {  
         $this.height(value);  
      }  
   });  
  };  
})(jQuery); 

呼叫方法如下:

 $('div').resize('width', '600').css('color','blue'); 

 

 四、jQuery外掛編寫總結

 編寫jQuery外掛可以充分利用庫,將公用的函式抽象出來,“迴圈利用”。以下是簡短的總結:

  • 使用(function($){//plugin})(jQuery);來包裝你的外掛
  • 不要在外掛的初始範圍中重複包裹
  • 除非你返回原始值,否則返回this指標來保證可鏈式
  • 不要用一串引數,而是使用一個物件,並且設定預設值
  • 一個外掛,不要為jQuery.fn附上多個函式
  • 為你的函式,事件,資料附著到某個名稱空間

 

 五、參考資料

 jQuery外掛開發      http://www.cnblogs.com/playerlife/archive/2012/05/11/2495269.html

 jQuery鏈式操作如何實現以及為什麼要用鏈式操作    http://www.jb51.net/article/33342.htm

 

 作者:雲霏霏

QQ交流群:243633526

 部落格地址:http://www.cnblogs.com/yunfeifei/

 宣告:本部落格原創文字只代表本人工作中在某一時間內總結的觀點或結論,與本人所在單位沒有直接利益關係。非商業,未授權,貼子請以現狀保留,轉載時必須保留此段宣告,且在文章頁面明顯位置給出原文連線。

如果大家感覺我的博文對大家有幫助,請推薦支援一把,給我寫作的動力。

 

相關文章