选项卡实现案例方法
鼠标点击时,切换文本内容
方法一
1. 利用用户点击时,把索引传递进来,触发点击事件从而实现文本内容切换
<div class="tabBox" id="tabBox">
<ul>
<li class="active">新闻</li>
<li>电影</li>
<li>音乐</li>
</ul>
<div class="active">这座城市也太太太太太太“魔幻”了!</div>
<div>中国电影票房全球第一</div>
<div>告白气球</div>
</div>
<style>
.tabBox {
width: 500px;
margin: 100px auto;
}
.tabBox ul {
/*绝对定位*/
position: relative;
top: 1px;
/*向下走1px ,让li 和 div 的边框合并一起,没有缝隙*/
}
.tabBox ul li.active {
/*让当前的li,下边框覆盖着div的边框,我们让li的下边框是背景颜色-白色。
这样看上去就像是没有边框一样*/
border-bottom-color: #fff;
color: #f00;
}
.tabBox ul li {
display: inline-block;
margin-right: 10px;
padding: 0 5px;
line-height: 33px;
border: 1px solid #aaa;
}
.tabBox div {
width: 500px;
line-height: 148px;
text-align: center;
border: 1px solid #aaa;
display: none;
}
/*设置active 选中时的样式效果 需要用class名来*/
/* div.active (选中时) 问:div中需要加空格吗?
1. 此时如果加空格,是在div的后代中样式的active (在后代中进行筛选)
2. 不加空格,是在本标签中同级筛选(标签名叫div,并且同时具备.active的样式)*/
.tabBox div.active {
display: block;
}
</style>
//[思路:]
// 1. 给所有的Li都绑定点击事件,当点击任何一个Li的时候,都做第二步操作
// 2. 可以先让li 和div的样式清空:className=" ";
// 3. 再让当前点击的li和对应的div都有active样式.
// 1. 首先获取元素
var tabBox = document.getElementById('tabBox');
var tabList = tabBox.getElementByTagName('li');
var divList = tabBox.getElementByTagName('div');
// 2. 因每个li都要绑定一个事件,复制做某一件事,需要设定一个循环
for (var i =0; i<tabList; i++) {
// 3. 给每个li都注册一个点击事件。点击时做什么方法(可用函数封装一个方法,
// 可直接调用此方法)
/**==注意==**/
/* 此处需要给每个li设置一个自定义属性。为什么呢?
因为如果封装方法后,直接注册事件后调用方法函数,此时循环的结果为3.
具体解释原因:在最下面*/
tabList[i].myIndex = i; /* 自定义属性 */
tabList[i].onclick = function() {
// 5. 点击时,直接触发函数方法
changeTab(this.myIndex);
};
}
// 4. 用函数封装一个事件方法
function changeTab (n) {
/* 因创建方法的时候,此时后台还不知道用户到时具体点击的是哪一个,所以需要给一个入口,
让用户把点击的某一个li的索引传递进来,(或者是其他,此处规定的是传进来的是索引)
n 代表的是形参,设置形参,让用户点击时传过来的索引以实参方式转递给形参。*/
// 1. 让所有li都清空样式
for(var i =0; i < tabList; i++) {
tabList[i].className='';
divList[i].className='';
// 2. 设置当前点击的选中的样式,(点击当前li的时候,会触发选中时的样式)
tabList[n].className = 'active';
divList[n].className = 'active';
// 此时的n是用户点击时传递进来的索引
}
}
问:为什么需要设置自定义属性 ?
注册事件时,把当前点击的索引传递给封装的方法
- 但是
changeTab()
里的是参数,不是对应的用户点击进来的索引,而是循环传过来的[i]
。 - 因为给元素
.onclick
制定了一个方法,但是方法未执行(点击时才会执行方法),没有执行的只能算是创建方法(函数)。 - 方法是怎么创建的呢?
所以当第一次循环的时候,函数没有执行
// i=0 第一次循环
tabList[0].onclick = function() {
changeTab(i); /* 此时的 i 还是字符串 */
//1. 因当第一次循环时,事件里函数存的是代码字符串,所以方法里存的是字符,与li的循环第一次的[0]没有关系
// 条件成立,循环继续,i自身+1
// i++ 此时的i=1
// i=1 第二次循环
tabList[1].onclick = function() {
changeTab(i); /* 第二次循环里面的 i 也是字符串 */
// 第三步 i++ 此时的i=2
// i=2 第三次循环
tabList[3].onclick = function() {
changeTab(i); /* 第三次循环 i 还是等于字符串 */
// 第四步循环 i++ i=3
// 因为li的lengte长度索引为3,只有3个元素,最后的索引=2,所以条件不成立,循环结束。
// 循环结束后,最后的结束 i=3
此时每个Li都已经绑定好事件,提交,下一步用户点击li
如点击第二个Li的时候,把第二个li执行,函数执行时,创建一个私有作用域,把之前存的字符串当代码执行。
此时执行完后的结果,i = 3.
// i=1 第二次循环 (点击第二个Li的时候)
tabList[i].onclick = function() {
'changeTab(i)'; /*创建时,刚开始的是字符串*/
changeTab(i); /*用户点击,执行的是代码执行*/
// 代码执行时,循环结束为3,所以当前i=3,所以点击事件的时候,结果为3,没有选中样式。结果不对。
}
解决方案
给每个li设置各自的自定义属性,让每个Li都添加一个自己的属性,让自定义属性等于当前点击的li
li 打印出来的是一个集合,自定义属性:‘myIndex’,里面存储的是各自的索引(当前循环li的索引)
for (var i =0; i<tabList; i++) {
tabList[i].myIndex = i; /*i=当前循环li的索引*/
}
打印的集合:
HTMLCollection(3) {
0:{
…
myIndex: 0 ; }
1:{
…
myIndex: 1 ; }
2:{
…
myIndex: 2 ; }}
最后再设置li的点击事件方法。
tabList[i].onclick = function() }
// this:代表的是当前点击的这个li
changeTab(this.myIndex); /* => 需要索引*/
}
// 把当前的索引以实参传入changeTab(n)形参中,点击li时,触发事件方法运行,实现选项卡效果。
课后总结!