js高级—tab栏切换(面向对象做法)
程序员文章站
2022-05-30 13:30:11
...
<main>
<h4>
Js 面向对象 动态添加标签页
</h4>
<div class="tabsbox" id="tab">
<!-- tab 标签 -->
<nav class="fisrstnav">
<ul>
<li class="liactive"><span>测试1</span><span class="iconfont icon-guanbi"></span></li>
<li><span>测试2</span><span class="iconfont icon-guanbi"></span></li>
<li><span>测试3</span><span class="iconfont icon-guanbi"></span></li>
</ul>
<div class="tabadd">
<span>+</span>
</div>
</nav>
<!-- tab 内容 -->
<div class="tabscon">
<section class="conactive">测试1</section>
<section>测试2</section>
<section>测试3</section>
</div>
</div>
</main>
* {
margin: 0;
padding: 0;
}
ul li {
list-style: none;
}
main {
width: 960px;
height: 500px;
border-radius: 10px;
margin: 50px auto;
}
main h4 {
height: 100px;
line-height: 100px;
text-align: center;
}
.tabsbox {
width: 900px;
margin: 0 auto;
height: 400px;
border: 1px solid lightsalmon;
position: relative;
}
nav ul {
overflow: hidden;
}
nav ul li {
float: left;
width: 100px;
height: 50px;
line-height: 50px;
text-align: center;
border-right: 1px solid #ccc;
position: relative;
}
nav ul li.liactive {
border-bottom: 2px solid #fff;
z-index: 9;
}
#tab input {
width: 80%;
height: 60%;
}
nav ul li span:last-child {
position: absolute;
user-select: none;
font-size: 12px;
top: 0px;
right: 0;
display: inline-block;
width: 20px;
height: 20px;
background-color: red;
cursor: pointer;
}
.tabadd {
position: absolute;
/* width: 100px; */
top: 0;
right: 0;
}
.tabadd span {
display: block;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
border: 1px solid #ccc;
float: right;
margin: 10px;
user-select: none;
cursor: pointer;
}
.tabscon {
width: 100%;
height: 300px;
position: absolute;
padding: 30px;
top: 50px;
left: 0px;
box-sizing: border-box;
border-top: 1px solid #ccc;
}
.tabscon section,
.tabscon section.conactive {
display: none;
width: 100%;
height: 100%;
}
.tabscon section.conactive {
display: block;
}
<script type="text/javascript">
//定义一个that变量,让实例对象中的this进行赋值
var that;
class Tab{
constructor(id){
//将实力对象中的this赋值到that中
that = this;
//首先获取最大父盒子的元素 , 此处的this指向实力对象
//获取需要操作的标签
this.main = document.querySelector(id);
// //获取最大父盒子中的所有li
// this.lis = this.main.querySelectorAll('li');
// // 获取最大父盒子中的所有section
// this.sections = this.main.querySelectorAll('section');
//获取最大父盒子中的tabadd
this.add = this.main.querySelector('.tabadd');
//获取最大父盒子中的fisrstnav下的第一个元素标签 (li的父元素)
this.ul = this.main.querySelector('.fisrstnav ul:first-child');
//获取最大父盒子中的tabscon的元素标签 (tabscon父元素)
this.fsection = this.main.querySelector('.tabscon');
// //获取最大盒子中的icon-guanbi
// this.remove = this.main.querySelectorAll('.icon-guanbi')
this.init();
}
//设置一个初始化的函数,让相关元素绑定事件(主要就是添加相关的绑定事件)
init(){
//一初始化的时候就调用新的li和section(重新调用切记写在最前面,要不然添加时,最后一个li没有效果)
this.updateNode();
//循环li,进行添加绑定事件,此处的长度设置为实例对象中的写法//this.lis.length
for (var i = 0; i < this.lis.length; i++) {
// 此处为了后期与section进行绑定,利用实力对象形式设置一个变量保存每次遍历的索引
this.lis[i].index = i;
//会给每个li设置点击事件
//此处测试li是否已经可以点击,拿到索引号
// this.lis[i].onclick = function(){
// console.log(this.index);
// }
//每个li设置点击事件,触发toggleTab的函数效果
this.lis[i].onclick = this.toggleTab;
//给每个icon-guanbi按钮进行绑定事件
this.remove[i].onclick = this.removeTab;
//给每个span设置鼠标双击事件
this.spans[i].ondblclick = this.editTab;
//给每个sections绑定一个双击事件(此处因为所需要用到的方法跟span设置的事件方法一样,所以此处直接调用span的双击方法)
this.sections[i].ondblclick = this.editTab;
}
//添加事件不需要进行遍历
this.add.onclick = this.addTab;
}
//重新获取所有的小li和section
updateNode(){
//获取最大父盒子中的所有li
this.lis = this.main.querySelectorAll('li');
// 获取最大父盒子中的所有section
this.sections = this.main.querySelectorAll('section');
//获取最大盒子中的icon-guanbi
this.remove = this.main.querySelectorAll('.icon-guanbi')
//获取所有的li下的第一个span
this.spans = this.main.querySelectorAll('.fisrstnav li span:first-child')
}
/*****************************************************************************************************/
//1.切换功能
toggleTab(){
//在此处调用清楚样式的函数,此处的this修改为that,因为this的话只能理解为li调用了此方法
//其中还有sections的存在,因此用that进行包含
that.clearClass();
//测试li是否已经可以点击,拿到索引号
// console.log(this.index);
//此处的this指向的是li这个标签(谁调用了我,我就指向谁)
this.className = 'liactive';
//因为this指向的是li,li中没有conactive这个类名属性,所以this.sections[thsi.index] = 'conactive';
// 不管用,因此可以得到此conactive为constructor(实例对象)中的元素
// this.sections[thsi.index] = 'conactive';
//设置一个全局变量taht,对实例对象中的this进行赋值,进行调用
//因此此处的this,修改为that
that.sections[this.index].className = 'conactive';
}
//设置一个清楚样式的函数(清除所有li和section中的类)
clearClass(){
for (let i = 0; i < this.lis.length; i++) {
//清除li和sections下的所有类(此处用到排他思想处理)
this.lis[i].className = '';
//此处sections可以用that或者this,在调用方法时用that就可以了
that.sections[i].className = '';
}
}
/*****************************************************************************************************/
//2.添加功能
addTab(){
//进行排他思想,让创建的标签类达到比较好的效果
that.clearClass();
//绑定测试
// alert(123)
//为了生成的效果好看,添加个生成随机数
var random = Math.random();
//(1) 创建li元素和section元素
var li = '<li class="liactive"><span>新选项卡</span><span class="iconfont icon-guanbi"></span></li>'
var section = ' <section class="conactive">新内容'+ random +'</section>';
//(2) 将以下的两个元素添加到父元素中(利用insertAdjacentHTML方法进行子元素的添加,因为insertAdjacentHTML不局限于文字添加,方法中的beforeend,是将标签等信息放在盒子里面的最后一个)
//因为addTab指向的实例对对象,因此此处用that
that.ul.insertAdjacentHTML('beforeend',li);
that.fsection.insertAdjacentHTML('beforeend',section);
//此处在重新调用一次init方法;
that.init();
}
// 已经设置了 updateNode() 函数重新调用li和section的个数
/*****************************************************************************************************/
//3.删除功能
//给当前函数添加事件对象(事件参数),阻止事件冒泡行为
removeTab(e){
e.stopPropagation(); //利用事件参数阻止冒泡,防止出发li的点击事件
//此时会出现新增li中的删除按钮跟当前索引取不到一起,因此将获取关闭按钮的元素放到 updateNode()方法中重新获取即可
//引用父元素的索引号
var index = this.parentNode.index;
// 测试
console.log(index);
// remove() 方法则可以直接删除指定的元素
that.lis[index].remove();
that.sections[index].remove();
//此处调用init方法,为了让init方法执行 updateNode() 方法,即可拿到新的元素进行遍历使用
that.init();
//当我们删除的不是选中状态的li的时候,原来的选中状态li保持不变
//如果当前的标签存折liactive这个标签状态,就直接返回值,不必执行下面的代码
if(document.querySelector('.liactive'))return;
//当我们删除了选中状态的这个li的时候,让它的前一个li处于选定状态
//让index--;从而让前一个li为选中状态
index--;
//index--;于此同时自动调用lis的点击事件,让sections也属于选中状态
// that.lis[index].click();
//利用 && 对前后的效果进行判断 (&& 与)
that.lis[index] && that.lis[index].click();
}
/*****************************************************************************************************/
//4.修改功能
editTab(){
//先获取原来的文本文字
var str = this.innerHTML;
//双击禁止选定文字;
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty()
//测试
// alert(123)
//使鼠标双击到的标签设置为文本标签
this.innerHTML = '<input type="text" />';
//获取input标签,将原来的文本文字赋值给input
var input = this.children[0];
input.value = str;
//让文本框内的文字处于选定状态
input.select();
//当我们离开文本框,将文本框内的值设置给span
input.onblur = function(){
this.parentNode.innerHTML = this.value;
};
input.onkeyup = function(e){
if(e.keyCode === 13){
//手动调用表单失去焦点事件 不需要鼠标离开操作
this.blur();
}
}
}
}
//创建的实力对象必须存在实例函数的下面,不然执行结果为undeiful
//首先过去最大的父盒子元素
/*var a = */ new Tab('#tab');
// a.init();
</script>