jquery的插件機(jī)制
為了方便用戶創(chuàng)建插件,jquery提供了.extend()和.fn.extend()方法。
.extend(object) ,用于擴(kuò)展jQuery類本身,也就是用來在jQuery類/命名空間上增加新函數(shù),或者叫靜態(tài)方法. 例如 jquery內(nèi)置的 ajax方法都是用.ajax()這樣調(diào)用的,有點(diǎn)像 “類名.方法名” 靜態(tài)方法的調(diào)用方式。
$.extend({
minValue: function (a, b) {
// 比較兩個(gè)值,返回最小值
return a < b ? a : b;
}
});
//調(diào)用
var i = 100; j = 101;
var min_value = $.minValue(i, j); // min_value 等于 100
$.extend([deep], target, object1, [objectN]);
用一個(gè)或多個(gè)其他對(duì)象來擴(kuò)展一個(gè)對(duì)象,返回被擴(kuò)展的對(duì)象。
參數(shù)
deep:可選。如果設(shè)為true,則遞歸合并。
target:待修改對(duì)象,如果不指定target,則給jQuery命名空間本身進(jìn)行擴(kuò)展。
obj1:待合并到第一個(gè)對(duì)象的對(duì)象
objectN:可選。待合并到第一個(gè)對(duì)象的對(duì)象。
例:
var obj1 = { a: false, b: 1, c: "abc" };
var obj2 = { a: true, c: "def" };
$.extend(obj1, obj2);
// 輸出 obj1 = { a: true, b: 1, c: "def" }
套路:
var opts = $.extend({}, defaluts, options);
// 用自定義插件參數(shù)去覆蓋插件的默認(rèn)參數(shù)
$.fn.extend(object)擴(kuò)展 jQuery 元素集來提供新的方法(通常用來制作插件)。
$.fn = $.prototype = {
init: function( selector, context ) {.....};
};
原來 .fn =.prototype,也就是jQuery對(duì)象的原型。那jQuery.fn.extend()方法就是擴(kuò)展jQuery對(duì)象的原型方法。
自執(zhí)行的匿名函數(shù)/閉包
匿名函數(shù)最大的用途是創(chuàng)建閉包(這是JavaScript語言的特性之一),并且還可以構(gòu)建命名空間,以減少全局變量的使用。
封裝JQuery插件
接下來我們一起來寫個(gè) 監(jiān)聽文本框,動(dòng)態(tài)顯示下拉選項(xiàng) (類似搜索提示)插件
1.定一個(gè)閉包區(qū)域,防止插件"污染"
//閉包限定命名空間
(function ($) {
// do something
})(window.jQuery);
2.jQuery.fn.extend(object)擴(kuò)展jquery 方法,制作插件
//閉包限定命名空間
(function ($) {
$.fn.extend({
getAjaxOption:function(options){
// do something
}
});
})(window.jQuery);
3.給插件默認(rèn)參數(shù),實(shí)現(xiàn) 插件的功能
//閉包限定命名空間
(function ($) {
$.fn.extend({
getAjaxOption: function (options) {
var opts = $.extend({}, defaluts, options); // 使用jQuery.extend 覆蓋插件默認(rèn)參數(shù)
// 為body綁定事件,判斷當(dāng)點(diǎn)擊別的區(qū)塊,隱藏下拉選項(xiàng)區(qū)塊
$(document).on('click',function(event){
event = window.event || event;
var target = $(event.srcElement || event.target);
var is_select = opts.container_class+' *,'+opts.container_class+','+opts.target_class+' *,'+opts.target_class;
if(!target.is(is_select)){
$(opts.container_class).hide();
}
})
return this.each(function () { // 這里的this 就是 jQuery對(duì)象,這里 return 為了支持鏈?zhǔn)秸{(diào)用
// 遍歷所有選中的dom
var $this = $(this); // 獲取當(dāng)前dom 的 jQuery對(duì)象,這里的this是當(dāng)前循環(huán)的dom
console.log(opts); // opts為當(dāng)前所有的配置項(xiàng)
// 接下來,在當(dāng)前dom下生成下拉選項(xiàng)的dom元素
$this.parent().css('position','relative');
$this.addClass(opts.target_class.slice(1))
.after('<div class="'+opts.container_class.slice(1)+'">'+
'<div class="'+opts.container_class.slice(1)+'-box">'+
'<div class="'+opts.no_data_class.slice(1)+'">'+opts.no_data_msg+'</div>'+
'</div>'+
'</div>');
});
}
});
//默認(rèn)參數(shù)
var defaluts = {
container_class:'.container-options', // 下拉選項(xiàng)容器class
target_class:'.ajaxOptionThis', // 當(dāng)前dom的標(biāo)識(shí)class
option_class:'.item', // 生成的下拉選項(xiàng)的class
no_data_class:'.no-data', // 無數(shù)據(jù)時(shí)對(duì)應(yīng)項(xiàng)的class
no_data_msg:'未找到相關(guān)數(shù)據(jù)', // 無數(shù)據(jù)時(shí)對(duì)應(yīng)項(xiàng)顯示的文字信息
ajax_url:'******', // 請求的地址
ajax_type:'get', // 請求的類型
ajax_data:{ // 請求的額外參數(shù)
city : 'zg',
page : 1
},
ajax_keyword_name:'kw', // 請求的關(guān)鍵詞的name值,value值固定為當(dāng)前文本框的值
};
})(window.jQuery);
5.插件私有方法
有些時(shí)候,我們的插件需要一些私有方法,不能被外界訪問。
//私有方法,檢測用戶傳進(jìn)來的參數(shù)是否合法
function isValid(options) {
return !options || (options && typeof options === "object") ? true : false;
}
6.公共方法 給別人來擴(kuò)展你的插件 或者 返回一些回調(diào)api
// 公共方法
// 當(dāng)點(diǎn)擊了選項(xiàng)后的回調(diào)函數(shù),$this為當(dāng)前輸入框,that為當(dāng)前點(diǎn)擊的選項(xiàng),opts為插件的配置項(xiàng)集合
$.fn.getAjaxOption.clickCallback = function ($this,that,opts) {}
// 當(dāng)ajax返回成功后執(zhí)行的回調(diào)函數(shù),$this為當(dāng)前輸入框,response為后端返回的數(shù)據(jù),opts為插件的配置項(xiàng)集合
$.fn.getAjaxOption.successCallback = function ($this,response,opts) {}
完整的插件代碼如下:
<style>
.container-options{position:absolute;min-width:100%;left:0;background:#fff;z-index:1;display:none}
.container-options .container-options-box{margin-top:-1px;border:1px solid #ccc;max-height:150px;overflow:auto}
.container-options .item,.container-options .no-data{text-align:center;transition:all .3s;cursor:pointer;line-height:1;padding:8px 0;text-align:center}
.container-options .item:hover{color:#fff;background:#eb6120}
.container-options .no-data{display:none}
</style>
(function ($) {
$.fn.extend({
getAjaxOption: function (options) {
//檢測用戶傳進(jìn)來的參數(shù)是否合法
if (!isValid(options)) return this;
var opts = $.extend({}, defaluts, options);
$(document).on('click',function(event){
event = window.event || event;
var target = $(event.srcElement || event.target);
var is_select = opts.container_class+' *,'+opts.container_class+','+opts.target_class+' *,'+opts.target_class;
if(!target.is(is_select)){
$(opts.container_class).hide();
}
})
return this.each(function () {
var $this = $(this);
$this.parent().css('position','relative');
$this.addClass(opts.target_class.slice(1))
.after('<div class="'+opts.container_class.slice(1)+'">'+
'<div class="'+opts.container_class.slice(1)+'-box">'+
'<div class="'+opts.no_data_class.slice(1)+'">'+opts.no_data_msg+'</div>'+
'</div>'+
'</div>');
// 為當(dāng)前輸入框綁定 事件監(jiān)聽,動(dòng)態(tài)獲取值
$this.on('input',function(){
var data = {};
data[opts.ajax_keyword_name] = $.trim($this.val());
data = $.extend({}, opts.ajax_data, data);
if( data[opts.ajax_keyword_name].length <=0 ){ return false; }
$.ajax({
type:opts.ajax_type,
url :opts.ajax_url,
data: data,
success: function(response){
$.fn.getAjaxOption.successCallback($this,response,opts);
}
});
})
// 為下拉選項(xiàng)的每一項(xiàng)綁定click事件
$(opts.container_class).on('click',opts.option_class,function(){
$.fn.getAjaxOption.clickCallback($this,this,opts);
})
});
}
});
//默認(rèn)參數(shù)
var defaluts = {
// 容器dom
container_class:'.container-options',
target_class:'.ajaxOptionThis',
option_class:'.item',
no_data_class:'.no-data',
no_data_msg:'未找到相關(guān)數(shù)據(jù)',
ajax_url:'*****',
ajax_type:'get',
ajax_data:{
city : 'zg',
page : 1
},
ajax_keyword_name:'kw',
};
//公共方法
$.fn.getAjaxOption.clickCallback = function ($this,that,opts) {
$this.val($(that).text());
$(opts.container_class).hide();
}
$.fn.getAjaxOption.successCallback = function ($this,response,opts) {
$(opts.container_class).show().find(opts.option_class).remove();
if(response.data == "no result"){
$('.no-data',opts.container_class).show();
}else{
$('.no-data',opts.container_class).hide();
var list = '';
for (var i=0; i<response.data.list.length; i++){
list += '<div class="'+opts.option_class.slice(1)+'" data-id="'+response.data.list[i].id+'">'+response.data.list[i].name+'</div>';
}
$(opts.container_class+'-box').append(list);
}
}
//私有方法
function isValid(options) {
return !options || (options && typeof options === "object") ? true : false;
}
})(window.jQuery);