JQuery極大的提高了我們編寫JavaScript的效率,讓我們可以愉快的編寫代碼,做出各種特效。大多數情況下,我們都是使用別人開發的JQuery插件,今天我們就來看看如何把我們常用的功能做出JQuery插件,然后像使用jQuery那樣來操作DOM.
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會怎么樣。
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插件可以充分利用庫,將公用的函數抽象出來,“循環利用”。以下是簡短的總結:
- 使用(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/
聲明:本博客原創文字只代表本人工作中在某一時間內總結的觀點或結論,與本人所在單位沒有直接利益關系。非商業,未授權,貼子請以現狀保留,轉載時必須保留此段聲明,且在文章頁面明顯位置給出原文連接。
如果大家感覺我的博文對大家有幫助,請推薦支持一把,給我寫作的動力。