源码
<!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 及其后代中的li和div(获取的范围就限定在tabBox中) var tabBox = document.getElementById('tabBox'), tabList = tabBox.getElementsByTagName('li'), contentList = tabBox.getElementsByTagName('div'); // console.log(tabBox, tabList, contentList); /* 优化:利用函数封装的机制,把点击每一个li要处理的事情(这些事情基本都相同)进行封装,以此来减少 页面中的冗余代码 */ function changeTab(i) { //1,清空所有li,div的选中样式 for (let index = 0; index < tabList.length; index++) { const element = tabList[index]; tabList[index].className = ''; contentList[index].className = ''; } //2,让点击的这个li和div有选中的样式(但是创建函数的时候还不知道点击的是哪一个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() { // 先让所有的li和div移除选中样式(循环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,清空所有li,div的选中样式 for (let index = 0; index < tabList.length; index++) { const element = tabList[index]; tabList[index].className = ''; contentList[index].className = ''; } //2,让点击的这个li和div有选中的样式(但是创建函数的时候还不知道点击的是哪一个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>