Tab组件
组件化的原则
一 、正交原则
正交原则类似数学中的直角坐标系
一个点只要在一条轴线上行走,他在其他两条轴上的坐标都不会改变。而在组件中,我们应该让html,css,js分离开来,尽量避免改动了其中一个,就造成了另外两个文件无法正常使用
举个例子
在tab组件中,点击哪一个标签,就要显示它下面的内容。一般人会使用$div.show()
与$.hide()
来控制内容的显示与隐藏。而这个jq的方法,其实是在html的行间样式上加上display:none/display:原来的状态
。用js去改变css,这样就违法了组件的正交原则,并且这个原来的状态,你很难判断它到底是什么,只要css一改变,这个状态就可能改变。
所以,比较正确的方法,应该是$div.addClass("active")
,这样就只是加了个class,js并没有干涉到css,符合正交原则
二 、面向接口原则
实现一个tab组件,如果一开始就想着内容应该怎么显示与隐藏,实现组件的细节,这是不对的。正确的方式应该是去想别人会怎么样去调用这个组件。如果使用者以new一个构造函数的方法去调用,那组件就要写成一个构造函数,再去考虑它要实现哪些功能,需要传进哪些参数
jq实现tab组件
效果展示
html
<div class="tabs">
<ol class="tabs-bar">
<li>1</li>
<li>2</li>
<li>3</li>
</ol>
<ol class="tabs-content">
<li>content-one</li>
<li>content-two</li>
<li>content-three</li>
</ol>
</div>
复制代码
为了能加上样式,所以class必须是组件规定的,这是一个小小的缺点
css
.tabs{
border:1px solid #ff7800;
width:94px;
}
.tabs > ol{//消除ol的默认样式
list-style:none;
margin:0;
padding:0;
}
.tabs > ol.tabs-bar{
display:flex;//flex默认让标签内的元素水平排列,
border-bottom:px solid #ff7800;
}
.tabs > ol.tabs-bar >li{
padding:10px;
border:1px solid #ff7800;
border-bottom:0;
color:#fff;
}
//鼠标移动到标签上时,出现hover的样式
.tabs > ol.tabs-bar > li:hover{
background-color:#ff78aa;
}
//当标签被选中时的样式
.tabs > ol.tabs-bar >li.active{
background-color:blue;
}
//内容默认是隐藏的
.tabs >ol.tabs-content>li{
display:none;
border:1px solid #ff7800;
}
//标签被选中时,内容显示
.tabs >ol.tabs-content>li.active{
display:block;
}
复制代码
js
//考虑到别人会用new一个函数的方式来调用,所以写成构造函数的方法
// new Tabs('.tabs');
function Tabs(element){
//传进来到参数是类名,要用jq选中
this.elements = $(element);
// 一个构造函数要有一个初始化的状态,
// 在tabs中就是刚开始还没点击时,默认选中的第一个标签和显示第一内容
this.init();//由init来做初始化
//初始化后,就要给每个元素绑定上事件
this.bindEvent();
}
复制代码
Tabs函数初始化的实现
Tabs.prototype.init = function(){
// 实现默认状态,选中第一个标签和显示第一个内容
// 因为可能由很多个tabs组件,所以这里要给选中的标签遍历一下
this.elements.each(function(index,item){
//遍历过后的item是个原生的dom,所以这里要再一次选中
$(item).children(".tabs-bar").children('li').first().addClass('active');
$(item).children(".tabs-content").children('li').first().addClass('active');
})
}
复制代码
Tabs函数绑定事件功能的实现
Tabs.prototype.bindEvent = function(){
// 为了性能,我们不可能给每个li标签绑定上事件,
// 我们可以利用事件捕获,给最外部的标签加上事件,来监听是不是li被点击了
this.elements.on("click",'.tabs-bar > li',function(e){
// 第二个参数是限定点击是li标签时才触发
$li = $(e.currentTarget);//这里currentTarget就是li标签,不过是原生的,
// 再jq中,只要是以形参的方式出现在jq的回调函数中的dom,都是原生dom,所以要记得用$再次选中
$li.addClass('active').siblings().removeClass('active');
// 点击了li标签后要知道他的序号,这样才能知道要显示哪个内容
var index = $li.index();
//closest()可以匹配离他最近的父级的元素,包括他自己本身
$li.closest('.tabs').children('.tabs-content')
.children("li").eq(index).addClass('active')
.siblings().removeClass('active')
// 在这里要注意,找 .tabs 标签不能 $('.tabs),因为你将匹配到多个dom,点击其中一个tab的标签,其他tab组件也会跟着变动
//所以,选中dom要从小到大去选,所以此处用$li.closest()
})
}
复制代码
结语
本文作者胡志武,写于2019/5/7,转载请注明出处,另外走过路过不要忘记点个赞哦。