之前在“圳品”信息系统使用了tab选项卡来显示信息,详见:
JavaScript编程实现tab选项卡切换的效果
在tab选项卡中使用其它<div>来显示信息就出现了问题,乱套了,比如下面的这段代码:
<!DOCTYPE html> <html> <head> <meta name="Author" content="PurpleEndurer"> <title>“圳品”信息系统</title> <style type="text/css"> *{padding:0px;margin: 0px;font:12px normal "microsoft yahei";} #tabs {width:1024px; padding:5px; height:850px; margin:20px;} #tabs ul {list-style:none; display: block; height:30px; line-height:30px; border-bottom:2px #33ffff solid;} #tabs ul li {background:#eee; cursor:pointer; float:left; list-style:none; height:28px; line-height:28px; margin:0px 3px; border:1px solid #aaaaaa; border-bottom:none; display:inline-block; width:180px; text-align: center; font-size: 15px;} #tabs ul li.show {background:#fff;border-top:2px solid #33ffff; border-left:2px solid #33ffff; border-right:2px solid #33ffff; border-bottom: 2px solid #fff; font-weight:bold; font-size: 20px;} #tabs div {height:800px; line-height: 25px; border:1px solid #33ffff; border-top:none; padding:5px;} .hide{display: none;} .blue{color:blue;} </style> <script type="text/javascript"> function initTab() { var oTab = document.getElementById("tabs"); var oUl = oTab.getElementsByTagName("ul")[0]; var oLis = oUl.getElementsByTagName("li"); var oDivs= oTab.getElementsByTagName("div"); for (var i= 0; i<oLis.length; i++) { oLis[i].index = i; oLis[i].onmousemove = oLis[i].onclick = function (){activeTab(this.index);}; } }//initTab() function activeTab(a) { var oTab = document.getElementById("tabs"); var oTabUl = oTab.getElementsByTagName("ul")[0]; var oTabLis = oTabUl.getElementsByTagName("li"); var oTabDivs = oTab.getElementsByTagName("div"); for (var n= 0; n < oTabLis.length; n++) { oTabLis[n].className = ""; oTabDivs[n].className = "hide"; }//for() oTabLis[a].className = "show"; oTabDivs[a].className = ""; } //activeTab(a) window.onload = function() { initTab(); } </script> </head> <body> <p>JavaScript编程实现tab选项卡切换的效果 @Edge浏览器</p> <div id="tabs"> <ul> <li class="show" title="符合条件的产品清单">清单</li> <li>区域分布分析</li> <li>产品类别分析</li> </ul> <div id="divZpList"> 符合条件的产品清单 <div id="div1" class="blue">选项卡1</div> </div> <div class="tabHide" id="divZpAreaDistNow"><!-- Area distribution //--> 区域分布分析 <div id="div2" class="blue">选项卡2</div> </div> <div class="tabHide" id="divZpTypeDistNow"><!-- Type distribution //--> 产品类别分析 <div id="div3" class="blue">选项卡3</div> </div> </body> </html>
可以看到,第1张选项卡中的<div id="div1" class="blue">选项卡1</div>消失了,而第2张和第3张选项卡的内容对调了。
导致问题的原因在于activeTab()函数中,根据函数参数a传递进来的活动选项卡的indax,默认为选项卡组中的每个项目卡里一对<li>的<div>的index是相同的,即第a个<li>对默认匹配第a个<div>,并将第a个<li>和第a个<div>设置为当前活动选项卡:
oTabLis[a].className = "show"; oTabDivs[a].className = "";
在选项卡组中的<div>与<li>数量相同时,这样默认是可以的,如<li>区域分布分析</li>与 <div class="tabHide" id="divZpAreaDistNow">匹配,这也是 JavaScript编程实现tab选项卡切换的效果 可以正常工作的原因。
但我们在选项卡组的<div>内引入其它的<div>,比如上面代码中的:
<div id="divZpList"> 符合条件的产品清单 <div id="div1" class="blue">选项卡1</div> </div>
这时选项卡组中的<div>数量大于<li>数量时,第a个<li>对匹配第a个<div>的这种默认关系就不一定准确了。在上面的演示代码中,第2个选项卡中的<li>(即<li>区域分布分析</li>)将会与第2个<div>(即<div id="div1" class="blue">选项卡1</div>)匹配,而不是与第3个<div>(即<div class="tabHide" id="divZpAreaDistNow">)匹配。
找到了原因后,就要想解决问题的办法。解决问题的关键是在进行选项卡切换时如何找到或确定与选项卡组中的与<li>匹配的<div>。
解决这个问题的方法有很多,最直接的办法是定义一个全局的二维数组,把每个选项卡中的<li>和与之匹配的<div>的id保存下来,再用一个全局变量来存放当前活动选项卡的index。但是这样做的话,使用全局变量太多,耦合度低,不够通用。
我使用的解决办法是,先为选项卡中与<li>匹配的<div>设置一个特定的id特征码,比如id都是以"ZpDiv"来开头,然后遍历选项卡中的<div>,并把id中具有id特征码的<div>筛选出来,将其id值保存在一维数组aDivs中,这样第i个<li>就与aDivs[i]存储的id所指向的<div>匹配,然后可以进行相应的操作了。
如果我们在activeTab()中实现上述遍历、筛选和匹配工作的话,每次选项卡切换都要重复进行一次,不划算。
如果我们在选项卡组初始化阶段initTab()完成实现上述遍历、筛选和匹配工作,再把这种匹配关系传递到activeTab()中,就方便多了。
那么如何把这种匹配关系传递到activeTab()中呢?
既然我们先前是通过给选择卡的<li>增加index属性来确定当前活动选项卡的,那么我们再给<li>再增加两个属性,一个是.linkedDivID 用来存与它匹配的<div>的id,另一个是.TabsID ,用来保存<li>所在选项卡组的id。
具体实现起来,我使用的解决办法是,分三步:
第一步,为选项卡中与<li>匹配的<div>设置一个特定的id特征码,比如id都是以"ZpDiv"来开头。
第二步,在选项卡组初始化阶段initTab(),我们先遍历选项卡中的<div>,并把id中具有id特征码的<div>筛选出来,将其id值保存在一个一维数组aDivs中;然后遍历选项卡中的<li>,为每个<li>增加index、.linkedDivID 和.TabsID属性并赋值,并把TabsID和index属性作为参数传递给activeTab(tabsId, a)。
第三步,在activeTab(tabsId, a)中,先根据tabsId建立选项卡中的<li>数组oTabLis ,然后遍历<li>数组oTabLis,将所有的选项卡设置为非活动状态,接着修改oTabLis[a]的className,把它设置为活动选项卡的<li>,最后修改oTabLis[a].linkedDivID指向的<div>的ClassName,把它设置为活动选项卡的<div>。
完整的代码如下,其中增加了一个<textarea>来显示程序运行数据,方便了解代码内部的运行情况:
<!DOCTYPE html> <html> <head> <meta name="Author" content="PurpleEndurer"> <title>“圳品”信息系统</title> <style type="text/css"> *{padding:0px;margin: 0px;font:12px normal "microsoft yahei";} #tabsId {width:800px; padding:5px; height:300px; margin:20px;} #tabsId ul {list-style:none; display: block; height:30px; line-height:30px; border-bottom:2px #33ffff solid; } #tabsId ul li {background:#eee; cursor:pointer; float:left; list-style:none; height:28px; line-height:28px; margin:0px 3px; border:1px solid #aaaaaa; border-bottom:none; display:inline-block; width:180px; text-align: center; font-size: 15px; border-radius: 5px;} #tabsId ul li.tabShow {background:#fff;border-top:2px solid #33ffff; border-left:2px solid #33ffff; border-right:2px solid #33ffff; border-bottom: 2px solid #fff; font-weight:bold; font-size: 20px; border-radius: 5px;} #tabsId div {height:280px; line-height: 25px; border:1px solid #33ffff; border-top:none; padding:5px;} div.tabHide {display: none;} .blue {color:blue;} </style> </head> <body> <p>JavaScript编程实现tab选项卡切换的效果 @Edge浏览器</p> <div id="tabsId"> <ul> <li id="liZpList" class="tabShow" title="符合条件的产品清单">清单</li> <li id="liZpAreaDist">区域分布分析</li> <li id="liZppTypeDist">产品类别分析</li> </ul> <div id="divZpList"> 符合条件的产品清单 <div id="div1" class="blue">选项卡1</div> </div> <div class="tabHide" id="divZpAreaDistNow"><!-- Area distribution //--> 区域分布分析 <div id="div2" >选项卡2</div> </div> <div class="tabHide" id="divZpTypeDistNow"><!-- Type distribution //--> 产品类别分析 <div id="div3">选项卡3</div> </div> </div> <textarea border="1" id="taDebug" cols="180" rows="15">debug</textarea> <script type="text/javascript"> var taDbg = document.getElementById("taDebug"); const tabsIdZp = "tabsId"; //选项卡组(tabs)的id const tabDivIdTagZp = "divZp";//选项卡组(tabs) 中 与 <li> 配对的<div>的id特征码 // 设置当前活动的选项卡 //参数说明:tabsId:选项卡组(tabs)的id, a: 当前活动的选项卡中<li>的index function activeTab(tabsId, a) { taDbg.value += '\n\n activeTab begin------'; taDbg.value += '\n activeTab.index=' + a; var oTab = document.getElementById(tabsId); var oTabUl = oTab.getElementsByTagName("ul")[0]; var oTabLis = oTabUl.getElementsByTagName("li"); //将所有选项卡设置为非活动状态 var i; //divID for (var n = 0; n < oTabLis.length; n++) { oTabLis[n].className = ""; i = oTabLis[n]. linkedDivID; taDbg.value += '\n oTabLis[' + n + ']. linkedDivID=' + i + ' .className=' + oTabLis[n].className; document.getElementById(i).className = "tabHide"; taDbg.value += '\n oTabLis[' + n + '].id=' + oTabLis[n].id + ' .className=' + oTabLis[n].className; i = document.getElementById(i); taDbg.value += '\n Divs.id=' + i.id + ' .className=' + i.className; }//for() //设置当前活动的选项卡 oTabLis[a].className = "tabShow"; i = oTabLis[a]. linkedDivID; document.getElementById(i).className = ""; taDbg.value += '\nactiveTab end------'; } //activeTab() //初始化选项卡 //参数说明:tabsId: 选项卡组(tabs) id, tabDivIdTag:选项卡组(tabs) 中与<li>配对的<div>的id特征码 function initTab(tabsId, tabDivIdTag) { taDbg.value += '\n initTab() begin------'; var oTab = document.getElementById(tabsId); var oTabUl = oTab.getElementsByTagName("ul")[0]; var oTabLis = oTabUl.getElementsByTagName("li"); var oTabDivs= oTab.getElementsByTagName("div"); taDbg.value += '\n oTabDivs.length=' + oTabDivs.length; var aDivs = new Array();//用来存放选项卡组(tabs)中与<li>配对的<div>的id var iDividTagLen = tabDivIdTag.length; if (iDividTagLen==0) { //与<li>配对的<div>的id特征码为"",直接从oTabDivs生成 aDivs = Array.from(oTabDivs); } else { //遍历所有的<div> for (var i = 0; i<oTabDivs.length; i++) { //检查<div>的id是否符合与<li>配对<div>的id特征码 if (oTabDivs[i].id.substr(0, iDividTagLen) == tabDivIdTag) { //保存符合与<li>配对<div>的id特征码的<div> 的id aDivs.push(oTabDivs[i].id); } } } if (aDivs.length < oTabLis.length) { alert("<div>数量小于<li>数量,不能完成初始化"); } else { //初始化 for (var i = 0; i < oTabLis.length; i++) { oTabLis[i].index = i; //设置选项卡中<li>的index属性,用于确定当前活动选项卡 oTabLis[i].linkedDivID = aDivs[i]; //设置选项卡中<li>的linkedDivID属性,保存与该<li>配对的<div>的id oTabLis[i].TabsID = tabsId; //设置选项卡中<li>的TabsID属性,保存选项卡组的id taDbg.value += '\n oTabLis[' + i + '].id=' + oTabLis[i].id + ' linkedDivID=' + oTabLis[i].linkedDivID; oTabLis[i].onclick = function() {activeTab(this.TabsID, this.index);}; //oTabLis[i].onmousemove = oTabLis[i].onclick = function() {activeTab(this.TabsID, this.index);}; } //for }//if taDbg.value += '\n initTab() end------' }//initTab() window.onload = function() { //initTab(tabsId, tabLiId, tabDivId); initTab(tabsIdZp, tabDivIdTagZp); } </script> </body> </html>
代码运行效果如下:
嵌套的<div>内容都能正常显示出来。