title: 《鋒利的jQuery》十、jQuery插件的使用和寫法
date: 2017-07-24 06:20:00
tags: 鋒利的jQuery
編寫插件的目的是給已有的一系列方法或函數做一個封裝,以便在其他地方重復使用,方便后期維護和提高開發效率。
插件的種類
1.封裝對象方法的插件
這種插件是將對象方法封裝起來,用于通過選擇器獲取jQuery對象進行操作,是最常見的一種插件。比如parent()
、appendTo()
、addClass()
等。
2.封裝全局函數的插件
可以將獨立的函數加載到jQuery的命名空間之下。例如$.ajax()
、$.trim()
等。
3.選擇器插件
個別情況下,會需要使用到選擇器插件,雖然jQuery的選擇器十分強大,但還是會需要擴充一些自己喜歡的選擇器。
插件的基本要點
插件的文件名推薦命名為jquery.[插件名].js
。
所有的對象方法都應該附加到jQuery.fn對象上,而所有的全局函數都應該附加到jQuery對象本身上。
在插件內部,this
只想的是當前通過選擇器獲取的jQuery對象,例如click()
方法指向的是DOM元素。可以通過this.each來遍歷所有元素。
插件應該返回一個jQuery對象,以保證插件的可鏈式操作。除非插件需要返回的是一些需要獲取的量,例如字符串或者數組。
避免在插件內部使用$作為jQuery對象的別名,而應該用完整的jQuery來表示。這樣可以避免沖突,如果使用$作為jQuery的別名,要用必報來避免沖突。
插件中的閉包
利用閉包的特性,既可以避免內部臨時變量影響全局空間,又可以在插件內部繼續使用$作為jQuery別名。
(function($){ // 將$作為匿名函數的形參
// 這里編寫插件的代碼
var foo;
var bar = function(){
// 在匿名函數內部的函數都可以訪問foo,即便是在匿名函數的外部調用bar()的時候,也可以在bar()的內部訪問到foo,但在匿名函數的外部直接訪問foo是做不到的。
}
// 下面的語句讓匿名函數內部的函數bar()返回到全局可訪問的范圍內,這樣就可以在匿名函數的外部通過調用jQuery.BAR()來訪問內部定義的函數bar(),并且內部函數bar()也能訪問匿名函數內的變量foo。
$.BAR = bar;
})(jQuery) // jQuery作為實參傳遞給匿名函數
jQuery的插件機制
jQuery提供了兩個用于擴展jQuery功能的方法,jQuery.fn.extend()
方法和jQuery.extend()
方法。第一個方法用于封裝對象方法的插件,第二個適用于封裝全局函數插件和選擇器插件。這兩個方法都接收一個參數,類型是Object。
jQuery.extend()
除了擴展插件能用到,還有一個用處是擴展已有的對象,也就是傳遞兩個參數,類型都是object,第二個對象會和第一個對象合并,相同的屬性第二個會覆蓋第一個。
var settings = { validate: false , limit: 5 , name: 'foo' };
var options = { validate: true , name: 'bar' };
var newObj = jQuery.extend(settings,options);
console.log(newObj) // { validate: true , limit: 5 , name: 'bar' }
所以jQuery.extend()
方法經常用于設置插件方法的一些默認參數。
編寫jQuery插件
封裝jQuery對象插件
設置和獲取顏色的插件
首先編寫設置和獲取顏色的插件color。該插件的功能是:
- 設置匹配元素的顏色
- 獲取匹配的元素(元素集合中的第一個)的顏色。
由于是在jQuery對象上擴展方法所以使用jQuery.fn.extend
,這里要注意的是插件擴展內部的this指的是jQuery對象而不是普通的dom對象,然后插件如果不是返回字符串之類的特定值,應當使其具有可鏈接性,為此要直接返回這個this對象。
(function($){
$.fn.extend({
'color': function(value){
if(value == undefined){
return this.css('color'); // 獲取顏色。css方法本身就默認返回第一個的顏色
}else{
return this.each(function(){
$(this).css('color',value); // 設置顏色,由于this是jQuery對象,所以不需要each遍歷
})
}
}
});
})(jQuery)
表格隔行變色插件
(function($){
$.fn.extend({
'alterBgColor': function(options){
options = $.extend({
odd: 'odd', // 偶數行樣式
even: 'even', // 奇書行樣式
selected: 'selected' // 選中行樣式
},options);
$('tbody>tr:odd' , this).addClass(options.odd);
$('tbody>tr:even' , this).addClass(options.even);
$('tbody>tr' , this).click(function(){
// 判斷當前是否選中
var hasSelected = $(this).hasClass(options.selected);
// 如果選中,則移出selected類,否則就加上selected類
$(this)[hasSelected ? 'removeClass' : 'addClass'](options.selected).find(':checkbox').prop('checked',!hasSelected);
});
// 如果單選框默認情況下是選擇的,則高亮
$('tbody>tr:has(:checked)' , this).addClass(options.selected);
return this; // 返回this,可以繼續鏈式操作
}
});
})(jQuery)
需要注意的是上面兩個插件內部this都是可以匹配多個元素,但是如果遇到只能匹配一個元素的時候,要each遍歷匹配的jQuery對象,而在each內部,this就是dom對象不是jQuery對象了。
封裝全局函數
這類插件是在jQuery命名空間內部添加一個函數。
增加兩個函數,用于去除左側空格和右側空格。
(function($){
$.extend({
ltrim: function(text){
// 假如text是undefined等非正確參數,就取空字符串,防止replace方法報錯
return (text || '').replace(/^\s+/g,'');
},
rtrim: function(text){
return (text || '').replace(/\s+$/g,'');
}
})
})(jQuery)
由于是全局函數,所以要由jQuery或者$調用,不能用jQuery對象去調用。
$.ltrim(' text');
$.rtrim('text ');
自定義選擇器
jQuery提供了一套方法讓用戶客戶以通過制作選擇器插件來使用自定義選擇器。jQuery選擇器執行的步驟如下:
jQuery的選擇符解析器首先會使用一組正則表達式來解析選擇器
針對解析出的每個選擇符執行一個選擇器函數
根據這個函數返回的是
true
還是false
來決定是否保留這個元素。
按照上面的步驟,以$('div:gt(1)')
來舉例:
選擇器首先獲取所有的
div
元素逐個將這些
div
元素作為參數,連同括號里的1等一些參數一起傳遞給gt
對應的選擇器函數進行判斷如果
gt
對應的選擇器函數返回true
則這個div
元素保留,如果返回false
則不保留,這樣得到的結果就是一個符合要求的div
元素集合
現在來看一下最關鍵的gt
的選擇器函數:
gt: function(a,i,m){
return i > m[3] - 0;
}
選擇器一共接受三個參數:
第一個參數為a,指向的是當前遍歷到的dom元素。
第二個參數為i,指的是當前遍歷到的dom元素的索引值,從0開始。
第三個參數m最為特別,它是由jQuery正則解析引擎進一步解析后的產物(用match匹配出來的),m是一個數組。在這時m[3]的值就是'1'。
m[0]的值是:gt(1)
m[1]的值是:
m[2]的值是gt
m[4]在上面的例子沒有體現,假如是div:l(ss(dd))
這樣一個選擇器,m[4]就指向了(dd)
這部分,另外這里的m[3]的值就是ss(dd)
。
編寫一個between選擇器
例如使用$('div:between(2,5)')
能實現獲取索引3、4元素的功能。
選擇器僅僅是jQuery.expr[':']
對象的一部分,所以這里是將between
函數擴展到jQuery.expr[':']
對象中。
(function($){
$.extend(jQuery.expr[':'],{
between: function(a,i,m){
var tmp = m[3].split(','); // 將m[3]'最小值,最大值'改為['最小值','最大值']
return tmp[0] - 0 < i && i < tmp[1] - 0; // 將索引與最小和最大值進行比較,符合要求的返回true,這里-0 是隱式轉換的意思
}
})
})(jQuery)