jq实现Tab组件

1,837 阅读2分钟

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,转载请注明出处,另外走过路过不要忘记点个赞哦。