面向对象版Tab栏切换,(增加,删除,修改和切换)
<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;
background-color: pink;
z-index: 9;
}
#tab input {
width: 80%;
height: 60%;
}
nav ul li span:last-child {
position: absolute;
user-select: none;
font-size: 12px;
top: -18px;
right: 0;
display: inline-block;
height: 20px;
}
.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;
}
.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;
}
在做过webAPI之后一般这种普通版的tab栏的操作是很容易做出来的,如果说对面向对象这种方式不太理解,就以之前的方式写出来,然后在改成面向对象的,就容易理解的多了
//传统的DOM操作
var tab = document.querySelector('#tab');
var ul = document.querySelector('ul');
var lis = document.querySelectorAll('ul li');
var tabscon = document.querySelector('.tabscon');
var sections = document.querySelectorAll('section');
var tabadd = document.querySelector('.tabadd');
var iconfont = document.querySelectorAll('.iconfont');
var span = document.querySelectorAll('li span:first-child');
console.log(span);
// console.log(iconfont);
function toggleTab() {
for (var i = 0; i < lis.length; i++) {
lis[i].setAttribute('data-index', i)
lis[i].onclick = function () {
for (var i = 0; i < lis.length; i++) {
lis[i].className = '';
sections[i].className = ''
}
var index = this.getAttribute('data-index')
this.className = 'liactive';
sections[index].className = 'conactive'
}
}
}
function addTab() {
tabadd.onclick = function () {
for (var i = 0; i < lis.length; i++) {
console.log(lis[i]);
lis[i].className = '';
sections[i].className = ''
}
var li = ` <li class="liactive"><span>测试1</span><span class="iconfont icon-guanbi"></span></li>`
var section = `<section class="conactive">测试1</section>`
ul.innerHTML += li;
tabscon.innerHTML += section
}
}
function removeTab() {
console.log(lis);
// console.log(icofont);
for (var i = 0; i < iconfont.length; i++) {
iconfont[i].onclick = function (e) {
e.stopPropagation()
console.log(this.parentNode.getAttribute('data-index'));
var index = this.parentNode.getAttribute('data-index');
lis[index].remove()
}
}
}
function editTab() {
for (var i = 0; i < span.length; i++) {
span[i].ondblclick = function () {
var value = this.innerHTML;
this.innerHTML = `<input value = ${value}>`
var input = this.children[0];
input.onblur = function () {
this.parentNode.innerHTML = this.value;
}
}
}
}
removeTab()
toggleTab()
addTab()
editTab()
class Tab {
constructor(id) {
this.id = document.querySelector(id);
this.ul = this.id.querySelector('ul');
this.tabscon = document.querySelector('.tabscon');
this.tabadd = document.querySelector('.tabadd');
this.iconfont = document.querySelectorAll('.iconfont');
this.span = document.querySelectorAll('li span:first-child')
//用于存储定时器
this.timer = null
this.init()
}
//定义一个初始化的方法,由于在new完之后会执行构造函数的代码,所以,可以将init放在构造函数中调用,不需要再手动调用
init() {
//init()方法主要是对元素的操作行为(就是这个方法是干什么的),具体的操作行为写在相应的代码块中
this.updataNode()
//以点击事件为例:在点击tabadd的时候就执行addTab中的函数,也就是addTab是专门做了点击的这件事情
this.tabadd.onclick = this.addTab.bind(this.tabadd, this)
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].setAttribute('data-index', i)
this.lis[i].onclick = this.toggleTab.bind(this.lis[i], this);
this.iconfont[i].onclick = this.removeTab.bind(this.iconfont[i], this)
this.span[i].ondblclick = this.editTab.bind(this.span[i], this);
}
}
updataNode() {
this.lis = document.querySelectorAll('ul li');
this.sections = document.querySelectorAll('section');
this.iconfont = document.querySelectorAll('.iconfont');
this.span = document.querySelectorAll('li span:first-child');
}
//切换,就是点谁谁高亮
toggleTab(that) {
//清除定时器,保证在单击事件中只能有一个定时器,
clearInterval(that.timer)
//定一个定时器,让其300毫秒后执行代码块,如果,点击之后高亮,就结束定时器
that.timer = setInterval(() => {
that.clearAll()
var index = this.getAttribute('data-index')
this.className = 'liactive';
that.sections[index].className = 'conactive'
if (this.className) {
clearInterval(that.timer)
}
}, 300)
}
//每次切换都需要
clearAll() {
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].className = '';
this.sections[i].className = ''
}
}
addTab(that) {
that.clearAll()
var li = ` <li class="liactive"><span>测试12</span><span class="iconfont icon-guanbi"></span></li>`
var section = `<section class="conactive">测试12</section>`
that.ul.innerHTML += li;
that.tabscon.innerHTML += section;
that.init()
}
removeTab(that, e) {
e.stopPropagation()
console.log(this.parentNode.getAttribute('data-index'));
var index = this.parentNode.getAttribute('data-index');
that.lis[index].remove()
that.sections[index].remove()
that.init()
if (!document.querySelector('.liactive')) {
if (index == 0) {
if (that.lis.length == 0) {
return
}
that.lis[0].className = 'liactive'
that.sections[0].className = 'conactive'
} else {
index--
that.lis[index].className = 'liactive'
that.sections[index].className = 'conactive'
}
}
}
editTab(that) {
//清除上一次的定时器
clearInterval(that.timer)
var value = this.innerHTML;
this.innerHTML = `<input value = ${value}>`
var input = this.children[0];
input.focus()
input.onblur = function () {
this.parentNode.innerHTML = this.value;
}
}
}
new Tab('#tab')
其实面向对象的这个tab栏的难点在于this指向的问题,例如: this.span[i].ondblclick = this.editTab.bind(this.span[i], this);
这个代码中,就双击编辑文字的
第一个this.span[i]中的this就是指向实例对象中的属性,
this.editTab也是实例对象中的方法,
bind(this.span[i], this)中的this.span[i]是bind改变this指向,将this指向点击事件中的触发者,第二个this,是实例对象中的this,作为参数传递到了editTab方法中,用that接收,所以在代码中的that其实就是面向对象的属性