前言:最近公司后台需要实现一个类似于选项卡的一个搜索,比如说点击手机型号,下面出现很多选项如苹果华为等,点击其中一项,再下面一行会出现你点击的这个选项,当当当,就像下图这样:
点击搜索按钮,会收集选择结果那一行需要的数据传递给后台。由于这种形式的搜索在其他页面还会出现很多,所以,需要我把他们进行一下封装,前提是从后台接收到的数据结构都是一样的。
关键词:$.fn $.extend prototype 选项卡 封装 ......
正文:
1、需求:
运营提了要求,像很多插件一样,当他们想要用的时候,只需要在html里面写一个带有class的div,在script里面写入function然后传入数据就行:
html:
......
......
script:
......
$('.box').tagRel({
data:${dataValue}
});
......
js:
(function($,window){
function tagRel(element,options){
this.element = $(element);
this.options = $.extend({}, options);
this._createDom();
this._tabInit();
this._tabToggle();
this._labelClick();
this._chosenClose();
}
tagRel.prototype = {
//0:createDom
_createDom : function(){
var data = this.options.data,//要循环的数组
divHiddenForm = '',//隐藏域,放在this.element的前面
diva= '',
divb= '',
divc= '',
divaLi = '',//diva的tabli
divbPane = '';//divb的tab-pane
//divbPaneLi = '';//divb的tab-pane-li
divHiddenForm = '';
//循环divaLi,divbPane
$.each(data,function(i,item){
......(省略)
})
diva = ''+
'标签:'+
''+divaLi+'
'+
'';
divb = ''+divbPane+'';
divc = ' ';
//1:this.element之前放入隐藏域
this.element.before(divHiddenForm);
//2:this.element里面放入tab-title-box
this.element.append(diva);
//3:this.element里面放入tab-content-box
this.element.append(divb);
//4:this.element里面放入tab-chosen-box
this.element.append(divc);
},
//1:tab初始化
_tabInit : function(){
$('.tab-li').eq(0).addClass('active');//第一个标签默认选中#
$('.tab-pane').eq(0).stop().fadeIn();//第一个div默认显示
},
//2:tab切换
_tabToggle : function(){
var self = this;
$('.tab-li').click(function(e){
var liIndex = $(this).index();
$(this).addClass('active');
$(this).siblings().removeClass('active');
$('.tab-pane').hide();
$('.tab-pane').eq(liIndex).stop().fadeIn();
})
},
//3:label点击
_labelClick : function(e){
...(省略,这里就是一个点击标签,下层结果出现标签的效果)
},
//4:chosenClose关闭
_chosenClose : function(e){
var self= this;
$(".layui-tab-close").live('click',function(e){
e.stopPropagation();
var dataId = $(this).closest('li').attr('data-id');
var targetli = $('.tab-content').find('li[data-id='+dataId+']');
targetli.removeClass('active');
$(this).closest('li').remove();
self._collection();
})
},
//5:collect:收集结果
_collection:function(){
//收集信息
var arr = [];
$('.chosen-box li').each(function(){
var key = $(this).attr('data-tag'),
keyValue =$(this).attr('data-val'),
json = {};
json.tagName = key;
json.tagValue = keyValue;
arr.push(json);
})//console.log(arr);//最终传输数据。
$('#hidden').val(JSON.stringify(arr));
}
}
$.fn.tagRel = function(options){
new tagRel(this,options);
}
})(jQuery,window);
好,上面是代码,下面就是几行重要代码的解析:
先看下面这张图片,比较直观:
这张图片是上述代码收缩了部分,比较能够突出我要说的重点:
重点一:
我们用写插件的人的思维来思考,我们肯定是需要一个函数的,这个函数要接受到script里面传过来的参数。所以,我们先写一个函数。就是上图中的函数一。
函数一接收了两个参数。一个是element,一个是options。element就代表着script里面是是哪个标签触发了这个函数,就是那个$(),里面是class。而options就是接收到的数据。
重点二:
$.extend({},options):
$.extend()有两种用法
一种是扩展方法。
另一种是合并对象获得一个新的对象。
这里,我们介绍一下合并对象这个方法:
一般的插件中,比如说拖拽插件,表格插件,都会有一些默认的参数,那是在具体实例化时数据参数未传进来的时候,这些默认的参数不会让展示出来的页面看起来垮掉,哈哈。
下面是找到的两个插件的默认参数default:
拖拽插件:
表格插件:
大家是否觉得有点不一样,其实,细心的人发现,本质上两个是一样的,只不过表格插件是合起来写了。
例如:
var settings={validate:false,limit:5,name:"sm"};
var defaults={validate:true,limit:2}
var settings=$.extend(defaults,settings);
结果:settings={validate:false,limit:5,name:"sm"}
重点三:
现在有了函数了,那么我们对于这个tab的一些操作都写在哪里呢,写在原型里吧,可随时取用。
重点四:
封装起来就可以了吗?不行的,因为我们每次传参数使用的时候是一个实例:
所以,最后那个函数的意思如下:
$.fn是指jquery的命名空间,加上fn上的方法及属性,会对jquery实例每一个有效。如扩展$.fn.abc()。
在 jQuery 中,fn 其实就是 JavaScript 中 propotype 的一个别名,$ 是 jQuery 的别名,所以
$.fn.tagRel等同于 jQuery.prototype.pluginName。举个简单的小例子:
('li') 是一个对象,它的 key 有 length,它的原型(共享属性)为 jQuery.prototype,jQuery.prototype 的 key 有 addClass、removeClass、text、html 和 on 等。 \.fn.tagRel表示创建一个 jQuery 的属性,通俗的说是写一个 jQuery 函数,tagRel才是函数名
eg:
$.fn.setRedText = function() {
return $(this).css("color", "red");
};
$("p").setRedText();