我们先来做一个简单案例,功能描述:有一排a标签,当点击时要弹出该标签的索引值。先思考下怎么做:
(1)循环所有a标签i,为其添加点击事件
(2)点击事件里在循环一遍所有a标签j,如果点击的j和循环的i相同的话我们就弹出j//?为什么要再循环一遍呢?来看看下面代码
<body>
<ul id="friedslink">
<li><a href="#">链接1</a></li>
<li><a href="#">链接2</a></li>
<li><a href="#">链接3</a></li>
<li><a href="#">链接4</a></li>
</ul>
</body>
<script type="text/javascript">
/**
* 函数:index(self,obj)
* 参数:self:当前对象,obj:整体对象
* 功能:取得参数对象在元素组中的位置索引
* 返回:Number
**/
var index = function(self,obj){
for(var i=0;i < obj.length;i++){
if(obj[i]==self){
return i;
}
}
}
var links = document.getElementById("friedslink").getElementsByTagName("a");
for(var i =0;i < links.length;i++){
links[i].onclick = function(){
var i = index(this,links);
console.log(i);
return false;//阻止默认动作。
}
}
</script>
图一.png
此时点击哪个链接就弹出该链接所在的标签堆里的索引值。
如果不循环第二次会怎么样?依旧上面的代码,把引入index函数的语句注释掉看看
//var i = index(this,links);
此时再去点击链接,弹出的却全都是4,为什么呢?这里要储备的知识有两点:
(1)事件里的函数会被放到消息队列,而循环是同步的,所以当页面打开时代码会一步步向下执行。当i为4时不符合条件,停止循环
(2)for循环中定义的变量i相当于是全局的变量,当我们去点击按钮时,循环已经执行完了,此时获取到的i就是循环结束后的4
(3)事件里的this代表的是调用该事件的对象,打印出此时的this看看
for(var i =0;i < links.length;i++){
links[i].onclick = function(){
//var i = index(this,links);
console.log(links);
console.log(this);
console.log(i)
return false;//阻止默认动作。
}
}
console.log('我是不符合条件的i:',i)
图二.png
我点击了
链接1
this指的是<li><a href="#">链接1</a></li>
再练看看index函数
var index = function(self,obj){
for(var i=0;i < obj.length;i++){
if(obj[i]==self){
console.log(obj[i]);//<li><a href="#">链接1</a></li>
console.log(self);//<li><a href="#">链接1</a></li>
return i;
}
}
}
我们再循环一遍时,去匹配拿this与一堆链接去对比,相同时就返回与this相同的那个链接在一堆链接中的索引值。
这种方法是可行,却不是优秀的代码,毕竟循环了两次,那有什么比较好的方法呢?
我们打印出 链接的数组console.log(links);如图二,把数组展开是怎样的呢?每个链接都是一个对象,对象里包含很多属性,
那我们不妨在
(1)第一次循环的时候就给每个链接对象都添加一个index属性,并且让index属性等于此时循环的i值(即该对象在数组中的索引值)
(2)我们说过事件里的this代表的是点击的对象,而我在循环的时候已经给每个对象的添加了index属性,那在事件里用this.index
是不是就可以得到点击对象的index值里,而这个值恰好与该对象在数组里的索引值一样(因为我们前面定义了links[i[.index = 1)
来看看改进的代码吧。
<html>
<body>
<ul id="friedslink">
<li><a href="#">链接1</a></li>
<li><a href="#">链接2</a></li>
<li><a href="#">链接3</a></li>
<li><a href="#">链接4</a></li>
</ul>
<script type="text/javascript">
var links = document.getElementById("friedslink").getElementsByTagName("a");
for(var i=0;i<links.length;i++){
links[i].index = i;//给每个a标签对象添加index属性,并把索引值赋值给它
links[i].onclick = function(){
console.log(this.index);
return false;
}
}
console.log('我是不符合条件的i:',i)
</script>
</body>
</html>
点击事件里的this.index就是对象自己的index属性,也就是我们赋值给它的索引值,如果还不是很理解,看看下图
图三.png
当打开数组里的a对象,能看到到里面的我们给它添加的index属性。
很多时候我们都会要用到这种技术,例如在选项卡里,点击tab时下面的内容框跟着跳转,是怎么做到的呢?先来看看html
<style>
body,ul,li{margin:0; padding:0; font:12px/1.5 arial;}
ul,li{list-style:none;}
.wrap{width:500px;height: 400px; margin:20px auto;}
#tab_t li{float:left;box-sizing: border-box; width:25%; height:25px;line-height:25px; text-align:center; border:1px solid #aaa;}
#tab_t li.act{background:#abcdef;}
#tab_c div{border:1px solid #ccc;width:100%;height:300px;display: none;}
#tab_c div.show{display: block;}
</style>
</head>
<body>
<div class="wrap">
<ul id="tab_t">
<li class="act">选择1</li>
<li>选择2</li>
<li>选择3</li>
<li>选择4</li>
</ul>
<div id="tab_c">
<div class="show">内容1</div>
<div>内容2</div>
<div>内容3</div>
<div>内容4</div>
</div>
</div>
</body>
图四.png
如何做到点击点击li标签的时候下面的div也跟着一起跳转呢?那是不是要用到tab的下标,那tab的下标是怎么跟con联系起来的?思路如下
要明白一点:循环是页面打开时就进行的,当我们去点击时,循环已经结束了,此时我们去获取的i的值为不符合循环条件的4
(1)获取索引的tab标签tab_t_li,和所有的con标签tab_c_li;
(2)循环tab标签的数组tab_t_li,并为每个li标签添加index属性;
(3)每次点击时都循环所以的tab和con,把他们的class样式去掉,然后为点击的对象(tab)和与该tab有相同索引的con添加class样式。
(4)点击的对象(tab)的索引值获取方法tab_t_li[this.index]
看看下面代码:
window.onload = function(){
var tab_t = document.getElementById("tab_t");
var tab_t_li = tab_t.getElementsByTagName("li");
var tab_c = document.getElementById("tab_c");
var tab_c_li = tab_c.getElementsByTagName("div");
var len = tab_t_li.length;
var i=0;
for(i=0; i<len; i++){
tab_t_li[i].index = i;//给tab_t_li添加index属性,并将索引值赋给它
tab_t_li[i].onclick = function(i){
/*
这里的this指的是调用该函数的对象tab_t_li[i],而这个对象我们给它添加了index属性,且该index属性的值等于tab_t_li[i]的i值。
该对象调用了点击事件,事件里的this指向的就是该对象,那么可以用this.index来获得该对象在tab_t_li数组里索引值
*/
for(i=0; i<len; i++){
tab_t_li[i].className = '';
tab_c_li[i].className = '';
}
console.log(this.index)
tab_t_li[this.index].className = 'act';
tab_c_li[this.index].className = 'show';
/*
//为什么要用this.index,不可以直接用i吗?对于这个疑问,可以先看看输出的i是什么
console.log(i);
//4,到最后i = 4,不符合i<len条件,停止循环
console.log(tab_t_li[i]);
//undefined ,循环完后,全局的变量i的值为4,而tab_t_li[length-1] = 3,所以tab_t_li[4]是不存在的,所以返回undefined。既然tab_t_li[4]都为undefined了,那么tab_t_li[4].classNama自然也是不存在的,所以下面两条语句都是错误的。
tab_t_li[i].className = 'act';//Cannot set property 'className' of undefined
tab_c_li[i].className = 'block';//Cannot set property 'className' of undefined
*/
}
}
}
或者用这种方式,但是原理都是一样的,看下面代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
.active{background: #9cc;}
.div2{width:300px;height: 200px;border:1px solid red;display: none;}
</style>
</head>
<body>
<div id="div1">
<input type="button" value="1" class="active"/>
<input type="button" value="2"/>
<input type="button" value="3"/>
<input type="button" value="4"/>
<div class="div2" style="display:block;">11</div>
<div class="div2">22</div>
<div class="div2">33</div>
<div class="div2">44</div>
</div>
<script type="text/javascript">
var box = document.getElementById("div1");
var btn = box.getElementsByTagName("input");
var con = box.getElementsByTagName("div");
for(var i=0;i<btn.length;i++){
btn[i].index = i;
btn[i].onclick = function(){
for(var i = 0;i<btn.length;i++){
btn[i].className = "";
con[i].style.display = "none";
}
this.className = "active";
con[this.index].style.display = "block";
}
}
</script>
</body>
</html>
图五.png
明白了这个原理之后,你会发现其实大多数的tab选项卡,一级菜单,二级菜单走的都是这个套路,下面我们来看看一级菜单。
一级菜单就是他自己,不用跟谁去相关联,但是也要用到for循环,和点击事件(或者鼠标移入移出事件)那么就要用到this了。
<ul id="nav">
<li><a href="#">aaa</a></li>
<li><a href="#">aaa</a></li>
<li><a href="#">aaa</a></li>
<li><a href="#">aaa</a></li>
</ul>
<script type="text/javascript">
var nav = document.getElementById("nav");
var navLi = nav.getElementsByTagName("li");
for(var i = 0;i<navLi.length;i++){
navLi[i].onmouseover = function(){
//this.style.background = '#f00'
this.setAttribute("class","demo");
}
navLi[i].onmouseout = function(){
//this.style.background = '#fff'
this.setAttribute("class","");
}
}
</script>
一级菜单.png
再来看看二级菜单
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
*{margin:0;padding:0;font-size:13px;list-style:none;}
.menu{width:210px;margin:50px auto;border:1px solid #ccc;}
.menu p{height:25px;line-height:25px;font-weight:bold;background:#eee;border-bottom:1px solid #ccc;cursor:pointer;padding-left:5px;}
.menu div ul{display:none;}
.menu li{height:24px;line-height:24px;padding-left:5px;}
</style>
</head>
<body>
<div class="menu" id="menu">
<div>
<p>Web前端</p>
<ul style="display:block">
<li>JavaScript</li>
<li>DIV+CSS</li>
<li>jQuery</li>
</ul>
</div>
<div>
<p>后台脚本</p>
<ul>
<li>PHP</li>
<li>ASP.net</li>
<li>JSP</li>
</ul>
</div>
<div>
<p>前端框架</p>
<ul>
<li>Extjs</li>
<li>Esspress</li>
<li>YUI</li>
</ul>
</div>
</div>
</body>
<script type="text/javascript">
window.onload=function(){
var menu=document.getElementById('menu'),
ps=menu.getElementsByTagName('p'),
uls=menu.getElementsByTagName('ul');
for(var i in ps){
ps[i].id=i;
ps[i].onclick=function(){
var u=uls[this.id];
if(u.style.display=='block'){
u.style.display='none';
}else{
u.style.display='block';
}
}
}
}
</script>
</html>
竖向折叠二级菜单.png
网友评论