在B站看到的学习视频 传送门
首先看一下效果
需求介绍
- 点击tab栏,实现切换效果
- 点击+号,实现添加tab项和内容项
- 点击X号,可以删除当前的tab项和内容项
- 点击tab项文字或者内容,可以修改里面的文字
抽取对象:tab对象
- 该对象具有切换功能
- 该对象具有添加功能
- 该对象具有修改功能
- 该对象具有删除功能
项目分析
项目初始化
应该让所有的li section X 已经添加按钮 都绑定事件
切换
- 让当前点击的li具有类名,兄弟去除类名
- 点击li的时候this指向为li,不是#tab,所以要注意this指向
添加
- 点击添加的时候,创建li和section
- 点击添加的时候,当前为选中,兄弟去掉类名
- 把添加的添加到对应的父组件中
不推荐使用createElement的原因是因为,li的元素比较多
element.insertAdjacentHtml() 可以直接讲字符串格式元素添加到父元素中
- 每次添加完成时候,要重新获取到新的li和section,绑定新的事件
- 点击的时候,this指向的是+按钮,注意this指向
删除
- 点击 X 的时候,可能会冒泡到父亲的切换事件, 要记得阻止冒泡
- 点击 X 的时候,他没有索引值,但是他的父亲有
- 每次删除完,重新获取一遍新的元素
编辑
- 双击选中 改变内容
如果双击的话 会默认选中文字,此时需要禁止双击选中文字
window.getSelection?window.getSelection().removeAllRanges():document.section.empty();
- 核心思路:双击文字时,里面成功一个文本框,当时去焦点或者摁下回车后,把文本框中的值赋给原先的元素
- 让文本框处于选中状态
- 当我们离开文本框的时候,把文本框的赋给font
话不多说上代码
JS
var _that;
class Tab {
constructor() {
_that=this
//首先要获取所有的元素,便于添加事件
this.tab=document.querySelector('#tab');
this.ul=this.tab.querySelector('ul')
this.section=this.tab.querySelector('.section')
this.add=this.tab.querySelector('.add')
this.init()
}
updateNode(){
//每次操作完成之后,需要从新获取li和section
this.liList=this.tab.querySelectorAll('li')
this.sectionList=this.tab.querySelectorAll('section')
this.xList = this.tab.querySelectorAll('li span')
this.fontList=this.tab.querySelectorAll('li font')
}
init(){
//初始化,让所有li X 都绑定事件
this.updateNode()
for(var i =0;i<this.liList.length;i++){
this.liList[i].index=i
this.liList[i].onclick=this.toggleTab
this.xList[i].onclick=this.delTab
this.fontList[i].ondblclick=this.editTab
this.sectionList[i].ondblclick=this.editTab
}
this.add.onclick=this.addTab
}
clearClass(){
//去除类名
for(var i =0;i<this.liList.length;i++){
this.liList[i].className=''
this.sectionList[i].className=''
}
}
toggleTab(){
//点击li的时候this指向为li,不是#tab,所以要注意this指向
_that.clearClass()
this.className='liActive'
_that.sectionList[this.index].className='sectionActive'
}
addTab(){
//点击的时候,this指向的是+按钮,注意this指向
//点击添加的时候,创建li和section
_that.clearClass()//每次点击添加的时候,当前为选中,兄弟去掉类名
var random=Math.random()
var li='<li class="liActive"> <font>新选项卡</font> <span>X</span></li>'
var section='<section class="sectionActive">选项卡'+random+'</section>'
//把添加的添加到对应的父组件中
//不推荐使用createElement的原因是因为,li脸的元素比较多
// element.insertAdjacentHtml() 可以直接讲字符串格式元素添加到父元素中
_that.ul.insertAdjacentHTML('beforeend',li)
_that.section.insertAdjacentHTML('beforeend',section)
//每次添加完成时候,要重新获取到新的li和section,绑定新的事件
_that.init()
}
delTab(e){
//点击 X 的时候,可能会冒泡到父亲的切换事件, 阻止冒泡
e. stopPropagation()
//点击 X 的时候,他没有索引值,但是他的父亲有
var index=this.parentNode.index
//点击 X 删除对应索引的 li section
//remove() 可以直接删除指定的元素
_that.liList[index].remove()
_that.sectionList[index].remove()
//每次删除完,重新获取一遍新的元素
_that.init()
//当选中的不是选中状态时,选中状态不变
if(document.querySelector('.liActive')) return;
//当删除选中状态的li时,让他的前一个li为选中状态
index--
//让他前一个li做一次点击事件
//第一个的时候,没有前一个,做一个判断
_that.liList[index] && _that.liList[index].click()
}
editTab(){
var str=this.innerHTML
//双击选中 改变内容
// 如果双击的话 会默认选中文字,此时需要禁止双击选中文字
window.getSelection?window.getSelection().removeAllRanges():document.section.empty();
//核心思路:双金文字时,里面成功一个文本框,当时去焦点或者摁下回车后,把文本框中的值赋给原先的元素
this.innerHTML='<input type="text" />'
var input = this.children[0]
input.value=str
//让文本框处于选中状态
input.select()
//当我们离开文本框的时候,把文本框的值给了font
input.onblur=function(){
this.parentNode.innerHTML=this.value
}
//按下回车的时候,把文本框的值,给了font
input.onkeyup=function(e){
if(e.keyCode===13){
//手动调用input失焦事件
this.blur()
}
}
}
}
new Tab()
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>
<style>
ul{
padding: 0;
margin: 0;
}
#tab{
width: 600px;
height: 400px;
position: relative;
border: 1px solid pink;
}
ul{
overflow: hidden;
border-bottom: 1px solid red;
}
ul li{
box-sizing: border-box;
list-style: none;
height: 50px;
width: 80px;
border: 1px solid red;
float: left;
position: relative;
text-align: center;
line-height: 50px;
}
ul li span{
position: absolute;
right: 0;
top: 0;
width: 15px;
height: 15px;
color: white;
background: black;
text-align: center;
line-height: 15px;
}
input{
width: 100%;
}
section input{
height: 100px;
width: 90%;
}
.section{
width: 100%;
height: 350px;
}
section{
display: none;
width: 100%;
height: 100%;
}
.add{
font-weight: bold;
position: absolute;
right: 5px;
top: 5px;
border: 1px salmon solid;
padding: 5px;
}
.liActive{
background-color: antiquewhite;
}
.sectionActive{
display: block;
}
</style>
</head>
<body>
<div id="tab">
<ul>
<li class="liActive"> <font>测试1</font> <span>X</span></li>
<li> <font>测试2</font> <span>X</span></li>
<li><font>测试3</font> <span>X</span></li>
</ul>
<div class="add">+</div>
<div class="section">
<section class="sectionActive">li1</section>
<section>测试2</section>
<section>测试三</section>
</div>
</div>
</body>
<script src="./index.js"></script>
</html>