閱讀424 返回首頁    go 阿裏雲 go 技術社區[雲棲]


舉例說明jquery插件的編寫方法

jquery插件開發分為類級別開發和對象級別開發

類級別($.extend)

jQuery.extend(object)類級別就是用來在jQuery類/命名空間上增加新函數,可以理解為拓展jquery類,最明顯的例子是$.ajax(...),ajax方法都是用jQuery.ajax()這樣調用的,有點像 “類名.方法名” 靜態方法的調用方式。開發擴展其方法時使用$.extend方法,即jQuery.extend(object);

jQuery.extend() 方法有一個重載

下麵我們也來寫個jQuery.extend(object)的例子:

jQuery.extend({
    "minValue": function (a, b) {
        return a < b ? a : b;
    },
    "maxValue": function (a, b) {
        return a > b ? a : b;
    }
});

調用:

var i = 100; j = 101;
var min_v = $.minValue(i, j); // min_v 等於 100
var max_v = $.maxValue(i, j); // max_v 等於 101

重載版本:jQuery.extend([deep], target, object1, [objectN])

用一個或多個其他對象來擴展一個對象,返回被擴展的對象

如果不指定target,則給jQuery命名空間本身進行擴展。這有助於插件作者為jQuery增加新方法

如果第一個參數設置為true,則jQuery返回一個深層次的副本,遞歸地複製找到的任何對象。否則的話,副本會與原對象共享結構

未定義的屬性將不會被複製,然而從對象的原型繼承的屬性將會被複製

參數:

deep: 可選。如果設為true,則遞歸合並。

target: 待修改對象。

object1: 待合並到第一個對象的對象。

objectN: 可選。待合並到第一個對象的對象

示例1:

//合並 settings 和 options,修改並返回 settings。
var settings = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
jQuery.extend(settings, options);
//結果:
settings == { validate: true, limit: 5, name: "bar" }

示例2:

//合並 defaults 和 options, 不修改 defaults。
var empty = {};
var defaults = { validate: false, limit: 5, name: "foo" };
var options = { validate: true, name: "bar" };
var settings = jQuery.extend(empty, defaults, options);
//結果:
settings == { validate: true, limit: 5, name: "bar" }
empty == { validate: true, limit: 5, name: "bar" }

這個重載的方法,我們一般用來在編寫插件時用自定義插件參數去覆蓋插件的默認參數

對象級別

對象級別則可以理解為基於對象的拓展,如$("#table").changeColor(...); 這裏這個changeColor呢,就是基於對象的拓展了。
開發擴展其方法時使用$.fn.extend方法,即jQuery.fn.extend(object);


## 首先準備好一個架子

;(function($){})(jQuery);

這個架子是你編寫插件代碼要寫入的空間,下麵簡單解釋一下這個架子

1.自執行的匿名函數:是指形如這樣的函數: 

(function {// code})();

在jQuery環境下封裝自己的插件,首先為避免與其他庫的衝突,需要在插件的後麵傳一個jQuery參數進去,對應的函數裏麵的參數寫入$

2 為避免出現問題,需在插件的前後加入分號(分號的增加並不會影響程序的運行)

3.為什麼```(function{// code})();```可以被執行, 而```function{// code}();```卻會報錯?

首先, 要清楚兩者的區別:``` (function {// code})```是表達式, ```function {// code}```是函數聲明.    

其次, js"預編譯"的特點: js在"預編譯"階段, 會解釋函數聲明, 但卻會忽略表式.    

當js執行到```function(){//code}();```時, 由於```function() {//code}```在"預編譯"階段已經被解釋過, js會跳過```function(){//code}```, 試圖去執行```();```, 故會報錯; 

當js執行到```(function {// code})();```時, 由於```(function{// code})```是表達式, js會去對它求解得到返回值, 由於返回值是一 個函數, 故而遇到```();```時, 便會被執行.

另外, 函數轉換為表達式的方法並不一定要靠分組操作符(),我們還可以用void操作符,~操作符,!操作符……
例如:

//bootstrap 框架中的插件寫法:
!function($){
  //do something;
}(jQuery);

(function($){
  //do something;
})(jQuery);
是一回事

匿名函數最大的用途是創建閉包(這是JavaScript語言的特性之一),並且還可以構建命名空間,以減少全局變量的使用

例如:

var a=1;
(function(){
var a=100;
})();
alert(a); //彈出 1


## 再上一個架子

;(function($){
$.fn.tab = function(options){
var defaults = {
//各種參數,各種屬性
}
var options = $.extend(defaults,options);
this.each(function(){ //沒有必要再作 $(this) ,因為"this"已經是 jQuery 對象了.$(this) 與 $($('.tab')) 是相同的
//各種功能
});
return this; //直接寫成return this.each()這裏可以省略
}
})(jQuery);

這個架子就是jQuery官方提供的一個標準化的開發模式

fn是什麼東西呢。查看jQuery代碼,就不難發現。

jQuery.fn = jQuery.prototype = {
init: function( selector, context ) {.....};
};

原來 ```jQuery.fn = jQuery.prototype```,也就是jQuery對象的原型。那```jQuery.fn.extend()```方法就是擴展jQuery對象的原型方法。我們知道擴展原型上的方法,就相當於為對象添加"成員方法",類的"成員方法"要類的對象才能調用,所以使用 jQuery.fn.extend(object)擴展的方法, jQuery類的實例可以使用這個“成員函數”。jQuery.fn.extend(object)和jQuery.extend(object)方法一 定要區分開來



$.fn.tab  tab是這個功能插件的名字,可任意改變名字

var options = $.extend(defaults,options);  這個是利用extend方法把 defaults對象的方法屬性全部整合到 options裏,也就是options繼承了defaults對象的方法以及屬性。這個defaults和options名字是可以隨意更改的,隻要是滿足js的命名規範

this.each(function(){});是實現功能代碼的地方

## tab選項卡實例

1.先備好html

  
  •     
  • html     
  • css     
  • js   
  
    
html
    
css
    
js
  
2.現在來寫插件代碼

;(function($){
$.fn.tab = function(options){
var defaults = {
//各種參數,各種屬性
}
var options = $.extend(defaults,options);
this.each(function(){
//各種功能 //可以理解成功能代碼
var _this = $(this);
_this.find('.tab_nav>li').click(function(){
$(this).addClass('current').siblings().removeClass('current');
var index = $(this).index();
_this.find('.tab_content>div').eq(index).show().siblings().hide();
});
});
return this;
}
})(jQuery);

3.在html代碼裏我們隻需要:

1) 找到外部容器,並調用你所寫的tab方法(就是你所寫的插件名字):

$.fn.tab = function(options){}

2) 作為可擴展性的插件代碼裏麵的class元素以及事件是不可以寫死的;解決這個問題就要在```var defaults = {}```中配置它

$.fn.tab = function(options){
var defaults = {
currentClass:'current',
tabNav:'.tab_nav>li',
tabContent:'.tab_content>div'
}
var options = $.fn.extend(defaults,options);
this.each(function(){
var _this = $(this);
_this.find(options.tabNav).click(function(){
$(this).addClass(options.currentClass).siblings().removeClass(options.currentClass);
var index = $(this).index();
_this.find(options.tabContent).eq(index).show().siblings().hide();
});
});
return this;
}

因為extends將default對象的屬性以及方法都整合到了options裏,這時候隻需要用options調用就可以了

4.同樣的如果需求是把click事件改為mouseover事件,此時我們需要用到on() or bind() ,這樣就方便我們改事件參數啦,如下:

$.fn.tab = function(options){
var defaults = {
currentClass:'current',
tabNav:'.tab_nav>li',
tabContent:'.tab_content>div',
eventType:'click'
}
var options = $.fn.extend(defaults,options);
this.each(function(){
var _this = $(this);
_this.find(options.tabNav).on(options.eventType,function(){
$(this).addClass(options.currentClass).siblings().removeClass(options.currentClass);
var index = $(this).index();
_this.find(options.tabContent).eq(index).show().siblings().hide();
});
});
return this;
}

因為需求是mouseover,這裏就不需要改插件源碼啦,直接在html裏的js代碼進行相應的變化就ok啦

5:jQuery最強大的特性之一莫過於鏈式操作,此時如果你在$('.tab').tab()後麵追加操作,你會發現無法實現,如下:

$('.tab').tab().find('.tab_nav>li').css('background','red');

但是當你return this把對象返回出去的時候你會發現又重新實現了

## 總結

jQuery 插件使庫把最有用的功能抽象成可重用代碼,這將進一步提高開發效率。下麵是你開發jQuery 插件時的注意事項:

總是把插件包裝在閉包中 { /* plugin goes here */ })( jQuery );

不在插件函數的立即作用域中額外包裝 this 關鍵字

總是讓插件函數返回 this 關鍵字以保持 chainability ,除非插件有真正的返回值

不要傳給插件大量參數,應該傳一個可以覆蓋插件默認選項的設置對象

在單個插件中,不要讓一個以上的名稱空間搞亂了 jQuery.fn 對象;總是為方法、事件和數據定義名稱空間

據說90%以上的插件就是用$.fn.extend()方式實現的,因為jquery的特色就是先選擇dom節點,然後鏈式處理這些節點。還有不常見的$.extend()插件編寫方式,該方式編寫的插件是在jquery命名空間內添加方法,也就是說在使用時不需要先選擇dom節點,使用時直接$.method()即可

接下來我們一起來寫個高亮的jqury插件

### 定一個閉包區域,防止插件"汙染"

(function ($) {})(window.jQuery); //window.jQuery = window.$ = jQuery;

### jQuery.fn.extend(object)擴展jquery 方法,製作插件

(function ($) { //閉包限定命名空間
$.fn.extend({
"highLight":function(options){
//do something
}
});
})(window.jQuery);

### 給插件默認參數,實現 插件的功能

//閉包限定命名空間
(function ($) {
$.fn.extend({
"highLight": function (options) {
var opts = $.extend({}, defaluts, options); //使用jQuery.extend 覆蓋插件默認參數
this.each(function () { //這裏的this 就是 jQuery對象
//遍曆所有的要高亮的dom,當調用 highLight()插件的是一個集合的時候
var $this = $(this); //獲取當前dom的jQuery對象,這裏this是當前循環的dom
$this.css({ //根據參數來設置 dom的樣式
backgroundColor: opts.background,
color: opts.foreground
});
});
}
});
var defaluts = { //默認參數
foreground: 'red',
background: 'yellow'
};
})(window.jQuery);

到這一步,高亮插件基本功能已經具備了。調用代碼如下:

$(function () {
$("p").highLight(); //調用自定義 高亮插件
});

這裏隻能直接調用,不能鏈式調用。我們知道jQuey是可以鏈式調用的,就是可以在一個jQuery對象上調用多個方法,如:

$('#id').css({marginTop:'100px'}).addAttr("title","測試“);

但是我們上麵的插件,就不能這樣鏈式調用了。比如:

$("p").highLight().css({marginTop:'100px'}); //將會報找不到css方法,原因在於我的自定義插件在完成功能後,沒有將 jQuery對象給返回出來

接下來,return jQuery對象,讓我們的插件也支持鏈式調用。(其實很簡單,就是執行完我們插件代碼的時候將jQuery對像return 出來,和上麵的代碼沒啥區別)

//閉包限定命名空間
(function ($) {
$.fn.extend({
"highLight": function (options) {
var opts = $.extend({}, defaluts, options); //使用jQuery.extend 覆蓋插件默認參數
return this.each(function () { /這裏的this 就是 jQuery對象。這裏return 為了支持鏈式調用
//遍曆所有的要高亮的dom,當調用 highLight()插件的是一個集合的時候
var $this = $(this); //獲取當前dom的jQuery對象,這裏this是當前循環的dom
$this.css({ //根據參數來設置 dom的樣式
backgroundColor: opts.background,
color: opts.foreground
});
});
}
});
var defaluts = { //默認參數
foreground: 'red',
background: 'yellow'
};
})(window.jQuery);

### 暴露公共方法給別人來擴展你的插件(如果有需求的話)
比如的高亮插件有一個format方法來格式話高亮文本,則我們可將它寫成公共的,暴露給插件使用者,不同的使用者根據自己的需求來重寫該format方法,從而是高亮文本可以呈現不同的格式

//公共的格式化方法. 默認是加粗,用戶可以通過覆蓋該方法達到不同的格式化效果
$.fn.highLight.format = function (str) {
return "" + str + "";
}

### 插件私有方法

有些時候,我們的插件需要一些私有方法,不能被外界訪問。例如 我們插件裏麵需要有個方法 來檢測用戶調用插件時傳入的參數是否符合規範    

### 其他的一些設置,如:為你的插件加入元數據插件的支持將使其變得更強大。

完整的高亮插件代碼如下:

//閉包限定命名空間
(function ($) {
$.fn.extend({
"highLight": function (options) {
if (!isValid(options))
return this;
var opts = $.extend({}, defaluts, options); //使用jQuery.extend 覆蓋插件默認參數
return this.each(function () { //這裏的this 就是 jQuery對象。這裏return 為了支持鏈式調用
//遍曆所有的要高亮的dom,當調用 highLight()插件的是一個集合的時候
var $this = $(this); //獲取當前dom 的 jQuery對象,這裏的this是當前循環的dom
//根據參數來設置 dom的樣式
$this.css({
backgroundColor: opts.background,
color: opts.foreground
});
//格式化高亮文本
var markup = $this.html();
markup = $.fn.highLight.format(markup);
$this.html(markup);
});
}
});

//默認參數
var defaluts = {
    foreground: 'red',
    background: 'yellow'
};
//公共的格式化 方法. 默認是加粗,用戶可以通過覆蓋該方法達到不同的格式化效果
$.fn.highLight.format = function (str) {
    return "<strong>" + str + "</strong>";
}
//私有方法,檢測參數是否合法
function isValid(options) {
    return !options || (options && typeof options === "object") ? true : false;
}

})(window.jQuery);

調用:

//調用:調用者覆蓋 插件暴露的共公方法
$.fn.highLight.format = function (txt) {
return "" + txt + ""
}
$(function () {
$("p").highLight({foreground: 'orange', background: '#ccc' }); //調用自定義高亮插件
});

最後更新:2017-06-15 12:01:54

  上一篇:go  WWDC上這個神級功能,一言不合又要改變未來購物趨勢
  下一篇:go  6.18不僅是電商購物街,還是互聯網建站節