index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>tab栏切换(面向对象)</title>
<link rel="stylesheet" href="./csss/style.css">
</head>
<body>
<main>
<h4>js面向对象 动态添加标签页</h4>
<div class="tabbox" id="tab">
<!-- tab标签 -->
<nav class="firstnav">
<ul>
<li class="liactive"><span>测试1</span><span class="icon"></span></li>
<li><span>测试2</span><span class="icon"></span></li>
<li><span>测试3</span><span class="icon"></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>
<script src="./js/tab.js"></script>
</body>
</html>
style.css
* {
margin: 0;
padding: 0;
/* css3盒子模型 */
box-sizing: border-box;
}
ul {
list-style: none;
}
/* tab 标签 */
#tab input {
width: 80%;
height: 60%;
}
.tabbox {
width: 800px;
height: 500px;
margin: 50px auto;
border: 1px solid lightsalmon;
}
.firstnav {
position: relative;
height: 100px;
}
ul li {
position: relative;
float: left;
width: 80px;
border-right: 1px solid #4c4c4c;
text-align: center;
line-height: 100px;
}
.liactive {
border-bottom: 2px solid #fff;
z-index: 9;
}
.tabadd {
position: absolute;
right: 10px;
top: 25px;
width: 50px;
height: 50px;
background-color: rgba(0, 0, 0, .3);
}
.tabadd span {
font-size: 50px;
line-height: 40px;
margin-left: 6px;
cursor: pointer;
}
.icon {
position: absolute;
top: 0;
right: 0;
width: 20px;
height: 20px;
}
.icon::after {
position: absolute;
top: -42px;
right: 0;
font-family: iconfont;
content: '\ea42';
font-size: 12px;
}
/* tab 内容 */
.tabscon {
height: 400px;
padding: 20px 20px;
box-sizing: border-box;
border-top: 1px solid #ccc;
}
section {
display: none;
}
.conactive {
display: block;
width: 400px;
height: 200px;
}
tab.js
var that;
class Tab {
constructor(id) {
//1.获取元素
this.main = document.querySelector(id);
this.add = this.main.querySelector('.tabadd');
//这句话不能写在这里,因为一开始调用时,未添加的将选择不到
//this.remove = this.main.querySelectorAll('.icon')
this.ul = this.main.querySelector('.firstnav ul:first-child');
this.tabscon = this.main.querySelector('.tabscon');
this.init();
that = this;
}
init() {
//这里必须加括号,因为需要立即执行,页面一开始就有li,
// 先执行constructor里的初始化函数,然后执行updatNode(),如果不能立即执行,
//将获取不到li不然下面的for不能获得长度等信息
this.updatedNode();
this.add.onclick = this.addTab;
// init 初始化操作,让相关的元素绑定事件
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].index = i;
//这里不跟小括号是因为点击才调用,而非直接调用
this.lis[i].onclick = this.toggleTab;
this.remove[i].onclick = this.removeTab;
this.span[i].ondblclick = this.editTab;
this.sections[i].ondblclick = this.editTab;
}
}
//去动态获取所有的li和section
updatedNode() {
this.lis = this.main.querySelectorAll('li');
this.sections = this.main.querySelectorAll('section');
this.remove = this.main.querySelectorAll('.icon');
this.span = this.main.querySelectorAll(".firstnav li span:first-child");
}
//1.切换功能
toggleTab() {
//这里用that是因为clearClass属于Tab里面的而不是toggleTab()里面的
that.clearClass();
this.className = 'liactive';
that.sections[this.index].className = 'conactive';
}
//2.添加功能
addTab() {
var random = Math.random();
//1.创建li元素和section元素
var li = '<li><span>新选项卡</span><span class="icon"></span></li>'
var section = '<section>测试' + random + ' </section>';
//2.把这两个元素追加到对应的父元素里面
that.ul.insertAdjacentHTML('beforeend', li);
that.tabscon.insertAdjacentHTML('beforeend', section)
//以前的做法是:动态创建元素createElement,但是元素里面内容较多,
//需要innerHTML赋值,appendChild追加到父元素里面
//现在高级的做法是,利用inserAdjacentHTMl()直接把字符串格式元素添加到父元素中
that.init();
//这句话是在调用添加li时,去执行updataNode()进行选取元素
}
//3.删除功能
removeTab(e) {
e.stopPropagation(); //阻止冒泡 防止发出li 的切换点击事件
var index = this.parentNode.index;
console.log(index);
//根据索引号删除对应的li和section remove()方法可以直接删除指定的元素
that.lis[index].remove();
that.sections[index].remove();
that.init();
// 1.当我们删除了不是选中的这个li的时候,原来选中状态不变
if (document.querySelector('.liactive')) return;
// 2.当我们删除了选中的这个li的时候,让他前一个li处于选中状态
index--;
//自动调用我们的点击事件,不需要鼠标触发
//前面为真才会调用后面。没有则为假,不执行后面,解决删除第一个报未定义的错误
that.lis[index] && that.lis[index].click();
}
//4.修改功能
editTab() {
var str = this.innerHTML;
//双击禁止选定文字
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty()
//双击生成文本框
this.innerHTML = '<input type="text">'
var input = this.children[0];
input.value = str;
input.select(); //默认是选中状态
//当我们离开文本框就把文本框里面的值给span
input.onblur = function() {
this.parentNode.innerHTML = this.value;
}
//按下回车也可以把文本框里面的内容给span
input.onkeyup = function(e) {
if (e.keyCode === 13) {
//自动调用表单失去焦点事件, 不需要鼠标离开操作
this.blur()
}
}
}
//5.清除功能
clearClass() {
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].className = '';
this.sections[i].className = '';
}
}
}
//创建第一个实例对象
const tab = new Tab('#tab');