1.实现三个标签的切换,不考虑那么多,只是实现点击menu1就显示content1;点击menu2显示content2;点击menu3显示content3。这个很容易实现:

<style type="text/css">
.tab
{width:400px;text-align:left;margin:10px;}
.tab-menuWrapper
{padding-left:20px;}
.tab-menuWrapper li
{float:left;display:inline;border:1px solid #333;border-bottom:none;margin-right:5px;cursor:pointer;}
.tab-contnetWrapper
{border:1px solid #333;clear:both;paddding:5px;}
</style>
<div class="tab">
<ul class="tab-menuWrapper">
<li id="tab-menu1">menu1</li>
<li id="tab-menu2">menu2</li>
<li id="tab-menu3">menu3</li>
</ul>
<div class="tab-contnetWrapper">
<div id="tab-content1">content1</div>
<div id="tab-content2" style="display:none;">content2</div>
<div id="tab-content3" style="display:none;">content3</div>
</div>
</div>
<script type="text/javascript">
var tabMenu1 = document.getElementById('tab-menu1'),
tabMenu2
= document.getElementById('tab-menu2'),
tabMenu3
= document.getElementById('tab-menu3'),
tabContent1
= document.getElementById('tab-content1'),
tabContent2
= document.getElementById('tab-content2'),
tabContent3
= document.getElementById('tab-content3');
tabMenu1.onclick
= function(){
tabContent1.style.display
="block";
tabContent2.style.display
="none";
tabContent3.style.display
="none";
}
tabMenu2.onclick
= function(){
tabContent1.style.display
="none";
tabContent2.style.display
="block";
tabContent3.style.display
="none";
}
tabMenu3.onclick
= function(){
tabContent1.style.display
="none";
tabContent2.style.display
="none";
tabContent3.style.display
="block";
}
</script>

2.这时增加需求,想把标签增加到5个或者增加到8个,依据上面的代码接下来就要复制代码改成相应的onclick事件,但是这样我们实现是在没完没了重复性的工作,想办法解决重复性工作的问题:

<div class="tab">
<ul class="tab-menuWrapper" id="tab-menuWrapper">
<li>menu1</li>
<li>menu2</li>
<li>menu3</li>
</ul>
<div class="tab-contnetWrapper" id="tab-contnetWrapper">
<div>content1</div>
<div style="display:none;">content2</div>
<div style="display:none;">content3</div>
</div>
</div>
<script type="text/javascript">
//取得标签及内容的节点,并以数组的形式保存在变量中
var tabMenus = document.getElementById('tab-menuWrapper').getElementsByTagName('li'),
tabContents
= document.getElementById('tab-contnetWrapper').getElementsByTagName('div');
//遍历数组,让标签监听click事件
for(var i=0,leng = tabMenus.length;i<leng;i++){
tabMenus[i].onclick
= function(){
for(var j=0,len = tabContents.length;j<len;j++){
tabContents[j].style.display
="none";
}
tabContents[i].style.display
= "block";
}
}
</script>

通过遍历标签数组,给每个标签添加click事件监听,比如:当点击第1个标签时,首先通过遍历把内容全部设成隐藏,然后再把相应的第1个内容显示。

预览发现浏览器报错:“tabContents[i] is undefined

<script type="text/javascript">
//取得标签及内容的节点,并以数组的形式保存在变量中
var tabMenus = document.getElementById('tab-menuWrapper').getElementsByTagName('li'),
tabContents
= document.getElementById('tab-contnetWrapper').getElementsByTagName('div');
//遍历数组,让标签监听click事件
for(var i=0,leng = tabMenus.length;i<leng;i++){
tabMenus[i].onclick
= function(){
for(var j=0,len = tabContents.length;j<len;j++){
tabContents[j].style.display
="none";
}
alert(i)
//3
tabContents[i].style.display = "block";
}
}
</script>

通过alert(i),发现点击时返回的始终是3,3,3并不是想要的0,1,2。这是为什么?

alert(i)只有在onclick事件发生时才会触发,当onclick触发时,弹出i的值,在函数内部并未定义变量i,这时去外层找,找到for循环里,这时i已经循环变成了3,所以alert(i)时会弹出3.

修复bug后的代码变成:

<script type="text/javascript">
//取得标签及内容的节点,并以数组的形式保存在变量中
var tabMenus = document.getElementById('tab-menuWrapper').getElementsByTagName('li'),
tabContents
= document.getElementById('tab-contnetWrapper').getElementsByTagName('div');
//遍历数组,让标签监听click事件
for(var i=0,leng = tabMenus.length;i<leng;i++){
(
function(_i){
tabMenus[_i].onclick
= function(){
for(var j=0,len = tabContents.length;j<len;j++){
tabContents[j].style.display
="none";
}
//alert(_i)
//3
tabContents[_i].style.display = "block";
}
})(i);
}
</script>

OK,现在可以了,这时无论我们添加几个标签切换,实现起来很容易了。

3.示例2中通过li,div标签来获取标签和内容组合,但是在实际工作中,往往标签切换的结构并不是这么简单,如果是一个复杂的标签切换的结构,再使用getElementsByTagName()方法就很悲剧了。

下面把html的结构变得复杂一些:

<div class="tab">
<ul class="tab-menuWrapper">
<li>menu1</li>
<li>menu2</li>
<li>menu3</li>
</ul>
<div class="tab-contnetWrapper">
<div>
<div>content1</div>
<ul>
<li>1</li>
<li>2</li>
</ul>
</div>
<div style="display:none;">
<div>content2</div>
<ul>
<li>3</li>
<li>4</li>
</ul>
</div>
<div style="display:none;">
<div>content3</div>
<ul>
<li>5</li>
<li>6</li>
</ul>
</div>
</div>
</div>

这时如果再使用示例2的脚本显然是不可以了,接下来修改脚本使它更通用。

通过给内容块添加样式名称用来用脚本选择。

<div class="tab">
<ul class="tab-menuWrapper">
<li class="J_tab-menu">menu1</li>
<li class="J_tab-menu">menu2</li>
<li class="J_tab-menu">menu3</li>
</ul>
<div class="tab-contnetWrapper">
<div class="J_tab-content">
<div>content1</div>
<ul>
<li>1</li>
<li>2</li>
</ul>
</div>
<div class="J_tab-content" style="display:none;">
<p>content2</p>
<div>abc</div>
</div>
<div class="J_tab-content" style="display:none;">
content3
</div>
</div>
</div>

接下来的脚本自定义了getElementsByClassName()方法

通过getElementsByClassName的方法来选择内容块

<script type="text/javascript">
var GLOBAL = {};
GLOBAL.namespace
= function(str){
var arr = str.split('.'),o = GLOBAL;
for(i = (arr[0] == GLOBAL)?1:0;i<arr.length;i++){
o[arr[i]]
= o[arr[i]]||{};
o
= o[arr[i]];
}
}
GLOBAL.namespace(
"Dom");
GLOBAL.Dom.getElementsByClassName
= function(str,root,tag){
if(root){
root
= (typeof root == "string")?document.getElementById(root):root;
}
else{
root
= document.body;
}
tag
= tag||'*';
var els = root.getElementsByTagName(tag),arr = [];
for(var i=0,leng = els.length;i<leng;i++){
var k = els[i].className.split(' ');
for(j = 0,len = k.length;j<len;j++){
if(k[j] == str){
arr.push(els[i]);
break;
}
}
}
return arr;
}
//取得标签及内容的节点,并以数组的形式保存在变量中
var tabMenus = GLOBAL.Dom.getElementsByClassName('J_tab-menu'),
tabContents
= GLOBAL.Dom.getElementsByClassName('J_tab-content');
//遍历数组,让标签监听click事件
for(var i=0,leng = tabMenus.length;i<leng;i++){
(
function(_i){
tabMenus[_i].onclick
= function(){
for(var j=0,len = tabContents.length;j<len;j++){
tabContents[j].style.display
="none";
}
tabContents[_i].style.display
= "block";
}
})(i);
}
</script>

这时就不用怕html结构复杂了吧。~~

4.但是问题又出现了,页面上有多个标签切换的模块,这时再使用示例3的脚本就会有问题了,这时可以考虑通过添加Id来控制选中的是哪个模块中的标签,但是这样,又会出现代码重复的问题:

<div class="tab" >>

脚本:

//取得标签及内容的节点,并以数组的形式保存在变量中
var tabMenus = GLOBAL.Dom.getElementsByClassName('J_tab-menu','tab-Wrapper'),
tabContents
= GLOBAL.Dom.getElementsByClassName('J_tab-content','tab-Wrapper');
//遍历数组,让标签监听click事件
for(var i=0,leng = tabMenus.length;i<leng;i++){
(
function(_i){
tabMenus[_i].onclick
= function(){
for(var j=0,len = tabContents.length;j<len;j++){
tabContents[j].style.display
="none";
}
tabContents[_i].style.display
= "block";
}
})(i);
}

通过复制上面的脚本把相应的ID进行替换来实现。

显然这种方法违背了代码复用的原则,接下来看修改的代码:

<div class="tab J_tab">
<ul class="tab-menuWrapper">
<li class="J_tab-menu">menu1</li>
<li class="J_tab-menu">menu2</li>
<li class="J_tab-menu">menu3</li>
</ul>
<div class="tab-contnetWrapper">
<div class="J_tab-content">
<div>content1</div>
<ul>
<li>1</li>
<li>2</li>
</ul>
</div>
<div class="J_tab-content" style="display:none;">
<p>content2</p>
<div>abc</div>
</div>
<div class="J_tab-content" style="display:none;">
content3
</div>
</div>
</div>
<div class="tab J_tab">
<ul class="tab-menuWrapper">
<li class="J_tab-menu">menu1</li>
<li class="J_tab-menu">menu2</li>
<li class="J_tab-menu">menu3</li>
</ul>
<div class="tab-contnetWrapper">
<div class="J_tab-content">
<div>content1</div>
<ul>
<li>1</li>
<li>2</li>
</ul>
</div>
<div class="J_tab-content" style="display:none;">
<p>content2</p>
<div>abc</div>
</div>
<div class="J_tab-content" style="display:none;">
content3
</div>
</div>
</div>
<div class="tab J_tab">
<ul class="tab-menuWrapper">
<li class="J_tab-menu">menu1</li>
<li class="J_tab-menu">menu2</li>
<li class="J_tab-menu">menu3</li>
</ul>
<div class="tab-contnetWrapper">
<div class="J_tab-content">
<div>content1</div>
<ul>
<li>1</li>
<li>2</li>
</ul>
</div>
<div class="J_tab-content" style="display:none;">
<p>content2</p>
<div>abc</div>
</div>
<div class="J_tab-content" style="display:none;">
content3
</div>
</div>
</div>

相应javascript代码,自定义getElementsByClassName()通过样式名称用来获取元素:

<script type="text/javascript">
var GLOBAL = {};
GLOBAL.namespace
= function(str){
var arr = str.split('.'),o = GLOBAL;
for(i = (arr[0] == GLOBAL)?1:0;i<arr.length;i++){
o[arr[i]]
= o[arr[i]]||{};
o
= o[arr[i]];
}
}
GLOBAL.namespace(
"Dom");
GLOBAL.Dom.getElementsByClassName
= function(str,root,tag){
if(root){
root
= (typeof root == "string")?document.getElementById(root):root;
}
else{
root
= document.body;
}
tag
= tag||'*';
var els = root.getElementsByTagName(tag),arr = [];
for(var i=0,leng = els.length;i<leng;i++){
var k = els[i].className.split(' ');
for(j = 0,len = k.length;j<len;j++){
if(k[j] == str){
arr.push(els[i]);
break;
}
}
}
return arr;
}
function setTab(root){
//取得标签及内容的节点,并以数组的形式保存在变量中
var tabMenus = GLOBAL.Dom.getElementsByClassName('J_tab-menu',root),
tabContents
= GLOBAL.Dom.getElementsByClassName('J_tab-content',root);
//遍历数组,让标签监听click事件
for(var i=0,leng = tabMenus.length;i<leng;i++){
tabMenus[i]._index
= i;
tabMenus[i].onclick
= function(){
for(var j=0,len = tabContents.length;j<len;j++){
tabContents[j].style.display
="none";
}
tabContents[
this._index].style.display = "block";
}
}
}
var tabs = GLOBAL.Dom.getElementsByClassName('J_tab');
for(var i=0;i<tabs.length;i++){
setTab(tabs[i]);
}
</script>

4.接下来给当前选中的标签项加个高亮效果:

CSS:

<style type="text/css">
.tab
{width:400px;text-align:left;margin:10px;}
.tab-menuWrapper
{padding-left:20px;}
.tab-menuWrapper li
{float:left;display:inline;border:1px solid #333;border-bottom:none;margin-right:5px;cursor:pointer;}
.tab-contnetWrapper
{border:1px solid #333;clear:both;paddding:5px;}
.tab-currentMenu
{background:#000;color:#fff;}
</style>

HTML:

<div class="tab J_tab">
<ul class="tab-menuWrapper">
<li class="J_tab-menu tab-currentMenu">menu1</li>
<li class="J_tab-menu">menu2</li>
<li class="J_tab-menu">menu3</li>
</ul>
<div class="tab-contnetWrapper">
<div class="J_tab-content">
<div>content1</div>
<ul>
<li>1</li>
<li>2</li>
</ul>
</div>
<div class="J_tab-content" style="display:none;">
<p>content2</p>
<div>abc</div>
</div>
<div class="J_tab-content" style="display:none;">
content3
</div>
</div>
</div>
<div class="tab J_tab">
<ul class="tab-menuWrapper">
<li class="J_tab-menu tab-currentMenu">menu1</li>
<li class="J_tab-menu">menu2</li>
<li class="J_tab-menu">menu3</li>
</ul>
<div class="tab-contnetWrapper">
<div class="J_tab-content">
<div>content1</div>
<ul>
<li>1</li>
<li>2</li>
</ul>
</div>
<div class="J_tab-content" style="display:none;">
<p>content2</p>
<div>abc</div>
</div>
<div class="J_tab-content" style="display:none;">
content3
</div>
</div>
</div>
<div class="tab J_tab">
<ul class="tab-menuWrapper">
<li class="J_tab-menu tab-currentMenu">menu1</li>
<li class="J_tab-menu">menu2</li>
<li class="J_tab-menu">menu3</li>
</ul>
<div class="tab-contnetWrapper">
<div class="J_tab-content">
<div>content1</div>
<ul>
<li>1</li>
<li>2</li>
</ul>
</div>
<div class="J_tab-content" style="display:none;">
<p>content2</p>
<div>abc</div>
</div>
<div class="J_tab-content" style="display:none;">
content3
</div>
</div>
</div>

Javascript:

<script type="text/javascript">
var GLOBAL = {};
GLOBAL.namespace
= function(str){
var arr = str.split('.'),o = GLOBAL;
for(i = (arr[0] == GLOBAL)?1:0;i<arr.length;i++){
o[arr[i]]
= o[arr[i]]||{};
o
= o[arr[i]];
}
}
GLOBAL.namespace(
"Dom");
GLOBAL.Dom.getElementsByClassName
= function(str,root,tag){
if(root){
root
= (typeof root == "string")?document.getElementById(root):root;
}
else{
root
= document.body;
}
tag
= tag||'*';
var els = root.getElementsByTagName(tag),arr = [];
for(var i=0,leng = els.length;i<leng;i++){
var k = els[i].className.split(' ');
for(j = 0,len = k.length;j<len;j++){
if(k[j] == str){
arr.push(els[i]);
break;
}
}
}
return arr;
}
function setTab(root){
//取得标签及内容的节点,并以数组的形式保存在变量中
var tabMenus = GLOBAL.Dom.getElementsByClassName('J_tab-menu',root),
tabContents
= GLOBAL.Dom.getElementsByClassName('J_tab-content',root);
//遍历数组,让标签监听click事件
for(var i=0,leng = tabMenus.length;i<leng;i++){
tabMenus[i]._index
= i;
tabMenus[i].onclick
= function(){
for(var j=0,len = tabContents.length;j<len;j++){
tabContents[j].style.display
="none";
}
tabContents[
this._index].style.display = "block";
var currentMenu = GLOBAL.Dom.getElementsByClassName('tab-currentMenu',root)[0];
if(currentMenu){
currentMenu.className
= "";
}
this.className = "tab-currentMenu";
}
}
}
var tabs = GLOBAL.Dom.getElementsByClassName('J_tab');
for(var i=0;i<tabs.length;i++){
setTab(tabs[i]);
}
</script>

效果:

javascript实现tab标签组件1

5.示例4里边的效果发现三个切换模块的高亮效果是相同的,但在实际的应用中也会出现高亮不同的情况,这个通过传参的形式来解决这个问题,首先新增两个样式:

<style type="text/css">
.tab
{width:400px;text-align:left;margin:10px;}
.tab-menuWrapper
{padding-left:20px;}
.tab-menuWrapper li
{float:left;display:inline;border:1px solid #333;border-bottom:none;margin-right:5px;cursor:pointer;}
.tab-contnetWrapper
{border:1px solid #333;clear:both;paddding:5px;}
.tab-currentMenu1
{background:#000;color:#fff;}
.tab-currentMenu2
{background:#f00;color:#fff;}
.tab-currentMenu3
{background:#00f;color:#fff;}
</style>

接着对javascript进行修改:

<script type="text/javascript">
var GLOBAL = {};
GLOBAL.namespace
= function(str){
var arr = str.split('.'),o = GLOBAL;
for(i = (arr[0] == GLOBAL)?1:0;i<arr.length;i++){
o[arr[i]]
= o[arr[i]]||{};
o
= o[arr[i]];
}
}
GLOBAL.namespace(
"Dom");
GLOBAL.Dom.getElementsByClassName
= function(str,root,tag){
if(root){
root
= (typeof root == "string")?document.getElementById(root):root;
}
else{
root
= document.body;
}
tag
= tag||'*';
var els = root.getElementsByTagName(tag),arr = [];
for(var i=0,leng = els.length;i<leng;i++){
var k = els[i].className.split(' ');
for(j = 0,len = k.length;j<len;j++){
if(k[j] == str){
arr.push(els[i]);
break;
}
}
}
return arr;
}
function setTab(root,currentClass){
//取得标签及内容的节点,并以数组的形式保存在变量中
var tabMenus = GLOBAL.Dom.getElementsByClassName('J_tab-menu',root),
tabContents
= GLOBAL.Dom.getElementsByClassName('J_tab-content',root);
//遍历数组,让标签监听click事件
for(var i=0,leng = tabMenus.length;i<leng;i++){
tabMenus[i]._index
= i;
tabMenus[i].onclick
= function(){
for(var j=0,len = tabContents.length;j<len;j++){
tabContents[j].style.display
="none";
}
tabContents[
this._index].style.display = "block";
var currentMenu = GLOBAL.Dom.getElementsByClassName(currentClass,root)[0];
if(currentMenu){
currentMenu.className
= "";
}
this.className = currentClass;
}
}
}
var tabs = GLOBAL.Dom.getElementsByClassName('J_tab');
setTab(tabs[
0],"tab-currentMenu1");
setTab(tabs[
1],"tab-currentMenu2");
setTab(tabs[
2],"tab-currentMenu3");

如果一个函数内某个因素很不稳定,我们可以将它从函数内部分离出来,以参数形式传入,从而将不稳定因素和函数解耦。

现在的效果:

javascript实现tab标签组件1

嗯,不错,呵呵。

通过检测className是否等于tab-currentMenu1,如果是,就把样式名称替换成“”,并且把当前点击标签的样式名称替换成tab-currentMenu1,但是这样操作存在一个问题,就是会把和脚本操作无关的样式名也进行了修改。

如:

开始的代码:

javascript实现tab标签组件1

操作之后发现样式名称被替换成了"":

javascript实现tab标签组件1

接下来通过自定义addClass及removeClass来解决这个bug,修改后的代码:

<script type="text/javascript">
var GLOBAL = {};
GLOBAL.namespace
= function(str){
var arr = str.split('.'),o = GLOBAL;
for(i = (arr[0] == GLOBAL)?1:0;i<arr.length;i++){
o[arr[i]]
= o[arr[i]]||{};
o
= o[arr[i]];
}
}
GLOBAL.namespace(
"Dom");
GLOBAL.Dom.getElementsByClassName
= function(str,root,tag){
if(root){
root
= (typeof root == "string")?document.getElementById(root):root;
}
else{
root
= document.body;
}
tag
= tag||'*';
var els = root.getElementsByTagName(tag),arr = [];
for(var i=0,leng = els.length;i<leng;i++){
var k = els[i].className.split(' ');
for(j = 0,len = k.length;j<len;j++){
if(k[j] == str){
arr.push(els[i]);
break;
}
}
}
return arr;
}
GLOBAL.Dom.addClass
= function(node,str){
var reg = new RegExp("(^|\\s+)"+str);
if(!reg.test(node.className)){
node.className
= node.className+" "+str;
}
}
GLOBAL.Dom.removeClass
= function(node,str){
var reg = new RegExp("(^|\\s+)"+str);
if(reg.test(node.className)){
node.className
= node.className.replace(reg,"");
}
}
function setTab(root,currentClass){
//取得标签及内容的节点,并以数组的形式保存在变量中
var tabMenus = GLOBAL.Dom.getElementsByClassName('J_tab-menu',root),
tabContents
= GLOBAL.Dom.getElementsByClassName('J_tab-content',root);
//遍历数组,让标签监听click事件
for(var i=0,leng = tabMenus.length;i<leng;i++){
tabMenus[i]._index
= i;
tabMenus[i].onclick
= function(){
for(var j=0,len = tabContents.length;j<len;j++){
tabContents[j].style.display
="none";
}
tabContents[
this._index].style.display = "block";
var currentMenu = GLOBAL.Dom.getElementsByClassName(currentClass,root)[0];
if(currentMenu){
GLOBAL.Dom.removeClass(currentMenu,currentClass);
}
GLOBAL.Dom.addClass(
this,currentClass);
}
}
}
var tabs = GLOBAL.Dom.getElementsByClassName('J_tab');
setTab(tabs[
0],"tab-currentMenu1");
setTab(tabs[
1],"tab-currentMenu2");
setTab(tabs[
2],"tab-currentMenu3");
</script>

相关文章:

  • 2021-07-15
  • 2021-09-10
  • 2021-10-19
  • 2022-01-11
  • 2021-08-26
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-08-14
  • 2022-02-01
  • 2021-10-27
  • 2021-11-07
  • 2022-02-18
  • 2022-12-23
  • 2021-10-13
相关资源
相似解决方案