jquery的插件机制
为了方便用户创建插件,jquery提供了.extend()和.fn.extend()方法。
.extend(object) ,用于扩展jQuery类本身,也就是用来在jQuery类/命名空间上增加新函数,或者叫静态方法. 例如 jquery内置的 ajax方法都是用.ajax()这样调用的,有点像 “类名.方法名” 静态方法的调用方式。
$.extend({
minValue: function (a, b) {
// 比较两个值,返回最小值
return a < b ? a : b;
}
});
//调用
var i = 100; j = 101;
var min_value = $.minValue(i, j); // min_value 等于 100
$.extend([deep], target, object1, [objectN]);
用一个或多个其他对象来扩展一个对象,返回被扩展的对象。
参数
deep:可选。如果设为true,则递归合并。
target:待修改对象,如果不指定target,则给jQuery命名空间本身进行扩展。
obj1:待合并到第一个对象的对象
objectN:可选。待合并到第一个对象的对象。
例:
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);
// 用自定义插件参数去覆盖插件的默认参数
$.fn.extend(object)扩展 jQuery 元素集来提供新的方法(通常用来制作插件)。
$.fn = $.prototype = {
init: function( selector, context ) {.....};
};
原来 .fn =.prototype,也就是jQuery对象的原型。那jQuery.fn.extend()方法就是扩展jQuery对象的原型方法。
自执行的匿名函数/闭包
匿名函数最大的用途是创建闭包(这是JavaScript语言的特性之一),并且还可以构建命名空间,以减少全局变量的使用。
封装JQuery插件
接下来我们一起来写个 监听文本框,动态显示下拉选项 (类似搜索提示)插件
1.定一个闭包区域,防止插件"污染"
//闭包限定命名空间
(function ($) {
// do something
})(window.jQuery);
2.jQuery.fn.extend(object)扩展jquery 方法,制作插件
//闭包限定命名空间
(function ($) {
$.fn.extend({
getAjaxOption:function(options){
// do something
}
});
})(window.jQuery);
3.给插件默认参数,实现 插件的功能
//闭包限定命名空间
(function ($) {
$.fn.extend({
getAjaxOption: function (options) {
var opts = $.extend({}, defaluts, options); // 使用jQuery.extend 覆盖插件默认参数
// 为body绑定事件,判断当点击别的区块,隐藏下拉选项区块
$(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对象,这里 return 为了支持链式调用
// 遍历所有选中的dom
var $this = $(this); // 获取当前dom 的 jQuery对象,这里的this是当前循环的dom
console.log(opts); // opts为当前所有的配置项
// 接下来,在当前dom下生成下拉选项的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>');
});
}
});
//默认参数
var defaluts = {
container_class:'.container-options', // 下拉选项容器class
target_class:'.ajaxOptionThis', // 当前dom的标识class
option_class:'.item', // 生成的下拉选项的class
no_data_class:'.no-data', // 无数据时对应项的class
no_data_msg:'未找到相关数据', // 无数据时对应项显示的文字信息
ajax_url:'******', // 请求的地址
ajax_type:'get', // 请求的类型
ajax_data:{ // 请求的额外参数
city : 'zg',
page : 1
},
ajax_keyword_name:'kw', // 请求的关键词的name值,value值固定为当前文本框的值
};
})(window.jQuery);
5.插件私有方法
有些时候,我们的插件需要一些私有方法,不能被外界访问。
//私有方法,检测用户传进来的参数是否合法
function isValid(options) {
return !options || (options && typeof options === "object") ? true : false;
}
6.公共方法 给别人来扩展你的插件 或者 返回一些回调api
// 公共方法
// 当点击了选项后的回调函数,$this为当前输入框,that为当前点击的选项,opts为插件的配置项集合
$.fn.getAjaxOption.clickCallback = function ($this,that,opts) {}
// 当ajax返回成功后执行的回调函数,$this为当前输入框,response为后端返回的数据,opts为插件的配置项集合
$.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) {
//检测用户传进来的参数是否合法
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>');
// 为当前输入框绑定 事件监听,动态获取值
$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);
}
});
})
// 为下拉选项的每一项绑定click事件
$(opts.container_class).on('click',opts.option_class,function(){
$.fn.getAjaxOption.clickCallback($this,this,opts);
})
});
}
});
//默认参数
var defaluts = {
// 容器dom
container_class:'.container-options',
target_class:'.ajaxOptionThis',
option_class:'.item',
no_data_class:'.no-data',
no_data_msg:'未找到相关数据',
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);