了解JavaScript的ES类封装和事件交互机制。
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>Document</title>
<link rel="stylesheet" href="./css/tab.css">
</link>
</head>
<body>
<main>
<h4>
JS 面向对象 动态添加标签页
</h4>
<div class="tabsbox" id="tab">
<!-- tab标签 -->
<nav class="firstnav">
<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="tabcon">
<section class="conactive">测试1</section>
<section>测试2</section>
<section>测试3</section>
</div>
</div>
</main>
</body>
<script src="./js/tab.js"></script>
</html>
CSS样式代码
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
/* 主体盒子 */
main {
display: block;
margin: 0 auto;
margin-top: 100px;
width: 800px;
height: 500px;
}
/* 标题 */
main h4 {
font-weight: 700;
text-align: center;
margin-bottom: 15px;
}
/* 标签页盒子 */
main .tabsbox {
width: 100%;
height: 480px;
border: 1px solid #ccc;
}
/* 导航选项 */
main .tabsbox nav {
display: flex;
justify-content: space-between;
border-bottom: 1px solid #ccc;
}
.firstnav {
height: 50px;
}
main .tabsbox nav ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
}
main .tabsbox nav ul li {
position: relative;
width: 100px;
height: 50px;
list-style: none;
text-align: center;
line-height: 50px;
border: 1px solid #ccc;
cursor: pointer;
}
/*被选中的Li的样式*/
.liactive {
border-bottom: none !important;
}
.iconfont {
position: absolute;
right: 0px;
top: 0px;
display: inline-block;
width: 20px;
height: 20px;
border: 1px solid #ccc;
border-radius: 10px;
}
.iconfont::after {
position: absolute;
content: "×";
font-size: 24px;
top: -15px;
left: 3px;
cursor: pointer;
}
/*增加按钮*/
main .tabsbox nav .tabadd {
align-self: center;
margin-right: 10px;
width: 32px;
height: 32px;
text-align: center;
line-height: 32px;
border: 1px solid #ccc;
}
main .tabsbox nav .tabadd:hover {
box-shadow: 3px 3px 5px #888888;
cursor: pointer;
}
/* 内容部分 */
main .tabsbox .tabcon {
margin: 0;
padding: 15px;
}
main .tabsbox .tabcon section {
display: none;
height: 400px;
}
.conactive {
display: block !important;
;
}
JS脚本控制代码
var _that
class Tab {
constructor(id) {
//获取元素
_that = this
this.main = document.querySelector(id)
this.add = this.main.querySelector('.tabadd')
//获取所有的关闭按钮
//li的父元素
this.ul = this.main.querySelector('.firstnav ul:first-child')
this.fsection = this.main.querySelector('.tabcon')
//绑定事件
this.init()
}
init() {
//获取所有的li和section元素
this.updateNode()
//初始化事件
this.add.onclick = this.addTab
for (let index = 0; index < this.lis.length; index++) {
this.lis[index].index = index //添加索引号
this.lis[index].onclick = this.toggleTab //绑定点击函数
this.removeBtns[index].onclick = this.removeTab //绑定点击函数-删除tab
this.spans[index].ondblclick = this.editTab //绑定双击函数-编辑edit
this.sections[index].ondblclick = this.editTab //绑定双击函数-编辑edit
}
}
//获取所有的li和section元素
updateNode() {
this.lis = this.main.querySelectorAll('li')
this.sections = this.main.querySelectorAll('section')
this.removeBtns = this.main.querySelectorAll('.icon-guanbi')
this.spans = this.main.querySelectorAll('.firstnav li span:first-child')
}
clearClass() {
//清除class样式
for (let index = 0; index < this.lis.length; index++) {
this.lis[index].className = ''
this.sections[index].className = ''
}
}
//1-切换功能
toggleTab() {
console.log(this.index)
//先清除样式
_that.clearClass()
//修改tab标签样式
this.className = 'liactive'
//修改显示的内容
_that.sections[this.index].className = 'conactive'
}
//2-添加功能
addTab() {
//清除原始元素的样式
_that.clearClass()
//创建新的tab
var li =
'<li class="liactive"><span>newTab</span><span class="iconfont icon-guanbi"></span></li>'
//并将其添加父元素中
_that.ul.insertAdjacentHTML('beforeend', li)
//创建新的和section
var section = '<section class="conactive">' + new Date() + '</section>'
//将其添加到父元素中
_that.fsection.insertAdjacentHTML('beforeend', section)
//刷新注册事件
_that.init()
console.log('addTab')
}
//3-删除功能
removeTab(e) {
//阻止事件向上冒泡-防止触发父元素li的点击事件
e.stopPropagation()
var index = this.parentNode.index
console.log(index)
//根据索引号删除对应的li和section-remove直接删除指定元素
_that.lis[index].remove()
_that.sections[index].remove()
//更新事件
_that.init()
//当删除的tab并非出于选中状态,那么原始的选中状态不变
if (document.querySelector('.liactive')) return
//当删除选中状态的li时,自动让前一个处于选中状态
index--
//主动调用tab标签的点击事件——无需鼠标触发
_that.lis[index] && _that.lis[index].click()
}
//4-修改功能
editTab() {
//先获取原始内容
var str = this.innerHTML
//双击禁止选中tab和tabpane的文字
window.getSelection ?
window.getSelection().removeAllRanges() :
document.selection.empty
//双击修改tab和tabpane的文字
this.innerHTML = '<input type="text" style="width:100%;height:100%"/>'
//获取文本狂
var input = this.children[0]
input.value = str
//控制文字处于选中状态
input.select()
//离开文本框,将文本框的值赋给span标签
input.onblur = function() {
this.parentNode.innerHTML = this.value
}
//键盘enter时,将文本框的值赋给span标签
input.onkeyup = function(e) {
//手动调用鼠标失去焦点事件
if (e.keyCode === 13) {
this.blur()
}
}
}
}
//创建Tab对象,自动调用内部成员函数
var tab = new Tab('#tab')