选项卡实例讲解

182 阅读1分钟

源码

<!DOCTYPE html><html lang="en">  <head>    <meta charset="UTF-8" />    <meta name="viewport" content="width=device-width, initial-scale=1.0" />    <meta http-equiv="X-UA-Compatible" content="ie=edge" />    <title>Document</title>    <link rel="stylesheet" href="reset.min.css" />  </head>  <style>    .tabBox {      margin: 20px auto;      width: 500px;    }    .tabBox .tab {      position: relative;      top: 1px;    }    .tabBox .tab:after {      display: block;      content: '';      clear: both;    }    .tabBox .tab li {      float: left;      margin-right: 10px;      padding: 0 10px;      height: 35px;      line-height: 35px;      font-size: 14px;      border: 1px solid #aaa;      background-color: #eee;      cursor: pointer;    }    .tabBox .tab li.active {      background-color: #fff;      border-bottom-color: #fff;    }    .tabBox div {      display: none;      padding: 10px;      height: 100px;      border: 1px solid #aaa;      background-color: #fff;    }    .tabBox div.active {      display: block;    }  </style>  <body>    <section class="tabBox" id="tabBox">      <!-- 页卡 -->      <ul class="tab clearfix">        <li class="active">编程</li>        <li>读书</li>        <li>运动</li>      </ul>      <!-- 页卡对应的内容(有几个也卡,对应几个内容) -->      <div class="active">编程可以使我“赚取高薪”</div>      <div>读书可以使我“修身养性”</div>      <div>运动可以使我“身体健康”</div>    </section>    <script>      var tabBox = document.getElementById('tabBox'),        tabList = tabBox.getElementsByTagName('li'),        contentList = tabBox.getElementsByTagName('div');      //   console.log(tabBox, tabList, contentList);      function changeTab(i) {        for (let index = 0; index < tabList.length; index++) {          const element = tabList[index];          tabList[index].className = '';          contentList[index].className = '';        }        tabList[i].className = 'active';        contentList[i].className = 'active';      }          for (var i = 0; i < tabList.length; i++) {        tabList[i].indexVal = i;        tabList[i].onclick = function() {          changeTab(this.indexVal);        };      }    </script>  </body></html>

js中带注释的

<script>      /*        点击tab-box的li中的任意一个,都让当前的li和其对应的div有选中的样式(class='active'),        因为只能同时选中一个,所以还需要让除选中的这个,其他的li,div 样式都移除         实现的方法1:点击某一个li,我先让所有的li和div都移除选中的样式,接着让当前选中有选中的样式            1,想要操作谁,就先获取谁            2,事件绑定            3,实现点击li要处理的事情    */      // 获取 tabBox 及其后代中的lidiv(获取的范围就限定在tabBox中)      var tabBox = document.getElementById('tabBox'),        tabList = tabBox.getElementsByTagName('li'),        contentList = tabBox.getElementsByTagName('div');      //   console.log(tabBox, tabList, contentList);      /*        优化:利用函数封装的机制,把点击每一个li要处理的事情(这些事情基本都相同)进行封装,以此来减少        页面中的冗余代码    */      function changeTab(i) {        //1,清空所有lidiv的选中样式        for (let index = 0; index < tabList.length; index++) {          const element = tabList[index];          tabList[index].className = '';          contentList[index].className = '';        }        //2,让点击的这个lidiv有选中的样式(但是创建函数的时候还不知道点击的是哪一个li呢,只有点击的        //时候知道,此时我们要把点击的是哪个作为一个形参,提供对应的入口)=>i形参变量,点击的是谁,就        //在执行changeTab的时候,把点击这一项的索引传递给它        tabList[i].className = 'active';        contentList[i].className = 'active';      }      // 绑定事件      /*        循环绑定点击事件(而不是一个个的绑定)        基于自定义属性解决方案实现,在之前的某个阶段,把一些信息当作自定义属性赋值给元素对象,        到后期,需要用到这些值的时候,我们从自定义属性中获取即可      */      for (var i = 0; i < tabList.length; i++) {        // tabList[i] 获取到的li元素对象(堆,有很多内置的属性,也可以设置自定义属性的)        // 每一轮循环的时候,给当前元素对象的堆内存中设置一个自定义属性 indexVal,属性值存储        // 当前li 元素对象的索引        /*            tabList = {                0:{indexVal:0},                1:{indexVal:1},                ...            }          */        tabList[i].indexVal = i;        tabList[i].onclick = function() {          // 传递当前点击这个li的索引          // this => 当前点击的这个li,而我们基于它的自定义属性indexVal,就可以拿到它的索引          changeTab(this.indexVal);        };      }    </script>

实现选项卡功能和细节优化(多种实现方式)

<!DOCTYPE html><html lang="en">  <head>    <meta charset="UTF-8" />    <meta name="viewport" content="width=device-width, initial-scale=1.0" />    <meta http-equiv="X-UA-Compatible" content="ie=edge" />    <title>Document</title>    <style>      /* 块级元素再一行展示的几种方法 */      /* 1 */      .tabBox .tab {        font-size: 0; /* 取消 display: inline-block属性的bug自带间隙的问题 */      }      .tabBox .tab li {        display: inline-block; /*使用该属性可以让块元素再一行展示,但是会自带间隙bug */        margin-right: 10px;        padding: 0 10px;        height: 35px;        line-height: 35px;        font-size: 14px;        border: 1px solid #aaa;      }      /* 2 */      .tabBox .tab:after {        display: block;        content: '';        clear: both;      }      .tabBox .tab li {        float: left;        margin-right: 10px;        padding: 0 10px;        height: 35px;        line-height: 35px;        font-size: 14px;        border: 1px solid #aaa;      }      /* 3 */      .tabBox .tab {        display: flex;        justify-content: flex-start;      }      .tabBox .tab li {        margin-right: 10px;        padding: 0 10px;        height: 35px;        line-height: 35px;        font-size: 14px;        border: 1px solid #aaa;      }    </style>  </head>  <body>    <script>      // 绑定事件的方法      //  给li绑定事件      tabList[0].onclick = function() {        //  先让所有的lidiv移除选中样式(循环tabList,有多少个li就循环多少次)        for (let index = 0; index < tabList.length; index++) {          const element = tabList[index];          tabList[index].className = '';          contentList[index].className = '';        }        tabList[0].className = 'active';        contentList[0].className = 'active';      };      tabList[1].onclick = function() {        for (let index = 0; index < tabList.length; index++) {          const element = tabList[index];          tabList[index].className = '';          contentList[index].className = '';        }        tabList[1].className = 'active';        contentList[1].className = 'active';      };      tabList[2].onclick = function() {        for (let index = 0; index < tabList.length; index++) {          const element = tabList[index];          tabList[index].className = '';          contentList[index].className = '';        }        tabList[2].className = 'active';        contentList[2].className = 'active';      };      /*        优化:利用函数封装的机制,把点击每一个li要处理的事情(这些事情基本都相同)进行封装,以此来减少        页面中的冗余代码    */      function changeTab(i) {        //1,清空所有lidiv的选中样式        for (let index = 0; index < tabList.length; index++) {          const element = tabList[index];          tabList[index].className = '';          contentList[index].className = '';        }        //2,让点击的这个lidiv有选中的样式(但是创建函数的时候还不知道点击的是哪一个li呢,只有点击的        //时候知道,此时我们要把点击的是哪个作为一个形参,提供对应的入口)=>i形参变量,点击的是谁,就        //在执行changeTab的时候,把点击这一项的索引传递给它        tabList[i].className = 'active';        contentList[i].className = 'active';      }      //  给li绑定事件      tabList[0].onclick = function() {        changeTab(0);      };      tabList[1].onclick = function() {        changeTab(1);      };      tabList[2].onclick = function() {        changeTab(2);      };      /* 循环绑定点击事件(而不是一个一个绑定) */      /* 这样写是不行的,点击每个li的时候,绑定事件函数中的i都是3(循环结束后的结果) */      for (var i = 0; i < tabList.length; i++) {        tabList[i].onclick = function() {          changeTab(i);        };      }      for (let index = 0; index < 3; index++) {        i = 0;        i = 1;        i = 2;      }      //结果 i的值是3      /* 循环绑定点击事件(而不是一个一个绑定) */      /* 这样写是不行的,点击每个li的时候,绑定事件函数中的i都是3(循环结束后i的结果) */      /*        i=0 第一轮循环 i++        tabList[0].onclick = function(){            此处是创建函数,函数存储的是一堆破字符串,我们看到的i,也只是一个字符串            'changeTab(i)';        }        i=1 第一轮循环 i++        tabList[0].onclick = function(){           'changeTab(i)';        }        i=2 第一轮循环 i++        tabList[0].onclick = function(){           'changeTab(i)';        }        i=3循环结束        ......        点击了第二个li,触发第二个li绑定的函数 changeTab(i)         此时的i已经是循环结束后的3 l      */      for (let i = 0; i < tabList.length; i++) {        tabList[i].onclick = function() {          changeTab(i);        };      }      box.onclick = function() {        //此时换没执行,只有当点击box的时候,函数才执行,也就是此处还是创建函数呢      };      // 循环绑定事件的正确方法      // 绑定事件      /*        循环绑定点击事件(而不是一个个的绑定)        基于自定义属性解决方案实现,在之前的某个阶段,把一些信息当作自定义属性赋值给元素对象,        到后期,需要用到这些值的时候,我们从自定义属性中获取即可      */      for (var i = 0; i < tabList.length; i++) {        // tabList[i] 获取到的li元素对象(堆,有很多内置的属性,也可以设置自定义属性的)        // 每一轮循环的时候,给当前元素对象的堆内存中设置一个自定义属性 indexVal,属性值存储        // 当前li 元素对象的索引        /*            tabList = {                0:{indexVal:0},                1:{indexVal:1},                ...            }          */        tabList[i].indexVal = i;        tabList[i].onclick = function() {          // 传递当前点击这个li的索引          // this => 当前点击的这个li,而我们基于它的自定义属性indexVal,就可以拿到它的索引          changeTab(this.indexVal);        };      }      //   其他的方案      /*        闭包        for(var i = 0;i < tabList.length;i++){            tabList[i].onclick = (function(i){                return function(){                    changeTab(i);                }            })(i)        }        let 和  var         for(let i = 0;i < tabList.length;i++){            tabList[i].onclick = function(){                changeTab(i)            }        }    */    </script>  </body></html>