js_tab栏切换+es6_动态添加标签页
1. js_tab栏切换原理
通过点击不同的tab实现展示不同的界面的效果,主要是通过对显示不同界面的盒子进行隐藏以及显示来实现的。
效果图如下:
HTML代码块
<div class="box">
<div class="boxHeader">
<ul>
<li class="choosed">tab1</li>
<li>tab2</li>
<li>tab3</li>
<li>tab4</li>
</ul>
</div>
<div class="boxFooter">
<div class="item display">tab1的内容</div>
<div class="item">tab2的内容</div>
<div class="item">tab3的内容</div>
<div class="item">tab4的内容</div>
</div>
</div>
css代码块
body {
background-color: #d1dad3;
}
.box {
margin: 0 auto;
text-align: center;
}
ul {
list-style-type: none;
display: flex;
text-align: center;
margin: 0 auto;
margin-top: 20px;
position: center;
background-color: #f1f3f4;
width: 400px;
border-bottom: 1px solid #db6f60;
}
ul li {
width: 50px;
height: 30px;
line-height: 30px;
text-align: center;
cursor: url("../imgs/right.png") ,auto;;
margin-right: 40px;
}
.boxHeader {
}
.boxFooter {
margin-top: 5px;
}
.item {
display: none;
}
.display {
display: block;
}
/*选中的状态*/
.choosed {
color: #fff;
background-color: #db6f60;
}
1.1思路
首先需要知道当前点击的tab是哪个tab,基于此类逻辑,最开始的时候需要对每个tab标签通过setAttribute(‘index’,i)方式添加自定义属性,并在为每个tab标签绑定点击处理事件中通过getAttribute(‘index’)方式获取当前点击tab的索引值,通过该索引值,获得需要显示的内容。因此实现该效果核心思想主要基于自定义属性的获取以及设置、内置属性的获取以及移除。
1.2 实现代码
// 获取所有的li标签
var lis = document.querySelector('.boxHeader').querySelectorAll('li');
// 获取li标签对应得内容
var liContents = document.querySelector('.boxFooter').querySelectorAll('div');
// li标签点击处理事件
for (var i = 0; i < lis.length; i++) {
// 为每个li标签添加自定义属性 来确定是哪个li标签
lis[i].setAttribute('index',i);
// 为每个li标签绑定点击事件 点击后进行颜色转换以及内容进行转变
lis[i].onclick = function () {
// 其他标签移除状态 其他标签内容进行移除操作
for (var j = 0; j < lis.length; j++) {
lis[j].removeAttribute('class');
liContents[j].className = 'item';
}
// 当前标签加上状态
this.className = 'choosed';
// 改变tab内容
liContents[this.getAttribute('index')].className = 'item display';
}
}
2 es6_面向对象动态添加标签页
2.1 功能预览
- 点击tab栏切换效果
- 点击➕,可添加tab项和内容项
- 点击❌,可以删除当前的tab项和内容项
- 双击tab项文字或者内容项文字,可以修改里面的文字内容
- 实现效果
2.2 结构代码
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" name="viewport" content="user-scalable=no">
<title>Js 面向对象 动态添加标签页</title>
<link rel="stylesheet" href="../css/tab.css">
<link rel="stylesheet" href="../css/style.css">
<script type="text/javascript" src="../js/practice2.js"></script>
<script src="../js/fastclick.js"></script>
</head>
<body>
<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>
</body>
</html>
tab.css
* {
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: -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;
}
style.css
@font-face {font-family: "iconfont";
src: url('./iconfont/iconfont.eot?t=1553960438096'); /* IE9 */
src: url('./iconfont/iconfont.eot?t=1553960438096#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAK4AAsAAAAABmwAAAJrAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCCcAp4fwE2AiQDCAsGAAQgBYRtBzAbpQXIrrApw71oi3CCOyzEy8RvE4yIN8TD036/zp03qCYRjaJZNBFFS/gREoRGipQKofjuNrb+9XbTqrmXcqWzfTRDqFqWkhAJzYToaE6LQ7Q30CirRqSKMnj58DdIdrNAdhoTQJa5VGfLrtiAy+lPoAcZdUC57UljTR4TMAo4oL0xiqwYG8YueIHPCdTqYajty/t+bUpmrwvEnUK42lQhLMssVy1UNhzN4kmF6vSQVvMY/T5+HEU1SUXBbti7uBBrx++cgqJULp0GhAgBna5AgSkgE0eN6R1NwTitNt0yAI5VG7wr/8AljmoX7K+zq+tBF1Q8k9JTPWp1AjnJDgCzmM3bU0V31dsvV3M2eC6fHjaGfX/qS7U5Gr58vj6uD0bgxudyrV/OtHHyP+NZnpO1txbktjdY+3FB61+7nxeOzq8niGYnRwT3v3aZxeXf6rrNxl5//49WlEtZUUL1Pj3Bv1EO7MuG2namrCkbvcnApLUJtWpRhv2tzlRLx43kQ7WO2/FW6c5QqDZEZnYKFeosoVK1NdSa5E/XaVM1Ra7BhAEQmk0kjV5QaLbIzG5U6HRRqTkK1DqJtivrjMT1zJaNnIsihAiyQE3JdbszcW0Xiadzdl4d8UO0HSUGNDNXzl2hifYSO5pPjrorgdjUAAavoa5TKDZVUXD3kuuOOzh70fShvUiN2owtNsRxIREIIiATUCYpGO2aqXy/CxEeHcfuaKrLDiGbQ5kcEMsNIK8M5qCmR3mn8RFHOpcECBtlAAwWIZ2OAqV5kQoJXHvShORYBzrDZKhhb3uT8QPlrA3bmsKZV6i89DiTV2o1AAAA') format('woff2'),
url('./iconfont/iconfont.woff?t=1553960438096') format('woff'),
url('./iconfont/iconfont.ttf?t=1553960438096') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('./iconfont/iconfont.svg?t=1553960438096#iconfont') format('svg'); /* iOS 4.1- */
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-guanbi:before {
content: "\e676";
}
2.3 功能拆解并分析实现
2.3.1 tab栏切换效果
- 实现步骤
- 获取所有的li标签
- 给每个li标签添加自定义属性
- 给每个li标签添加点击事件
- 点击处理函数中,为当前点击li标签添加选中状态class类liactive
- 实现代码
window.addEventListener('load',function () {
// var that;
class Tab {
constructor(attr) {
// 获取当前调用实例对象
// that = this;
// 获取tab盒子
this.tabBox = document.querySelector(attr);
// 1. 获取所有的li标签
this.lis = this.tabBox.querySelectorAll('li');
// 获取所有的section标签
this.sections = this.tabBox.querySelectorAll('section');
// 页面加载初始化绑定事件
this.init();
}
// 为每个标签初始化绑定事件绑定事件
init() {
// this指向当前Tab实例
// 给tab标签下的Li标签绑定点击事件并添加自定义属性
for (var i = 0; i < this.lis.length; i++) {
// 2. 给li标签添加自定义属性
this.lis[i].index = i;
// 3. this.toggleTab不加括号,只有当点击之后再调用
this.lis[i].onclick = this.toggleTab.bind(this.lis[i],this); // 并没有改变当前函数的this指向,只是将当前函数的this指向指回当前点击对象,并将全局this作为参数传入,避免定义全局this(that)
}
}
// 清除li标签和section标签所有的选中类
clear() {
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].className = '';
this.sections[i].className = '';
}
}
// 5. tab栏切换 这里的this 指向调用者 即当前点击li标签
// tab栏切换 这里的this 指向调用者 即当前点击li标签
toggleTab(that) {
// 先清除已选中类 由于this指向li标签 因此需要用全局that调用实例对象获取当前实例对象的方法clear
that.clear();
// 为当前点击的Li标签添加liactive
this.className = 'liactive';
// 为对应的section标签添加选中类conactive
that.sections[this.index].className = 'conactive';
}
new Tab('#tab');
})
2.3.2 点击➕添加tab项和内容项
- 实现步骤
- 获取➕元素对象
- 给➕元素对象绑定点击事件
- 点击处理事件通过insertAdjacentHTML 创建子tab项,以及内容项
- 实现代码
// 添加tab项和内容项
addTab(that) {
// 清除默认样式
that.clear();
var num = Math.floor(Math.random() * 20);
// 创建li标签
var li = '<li class="liactive"><span>新建tab页</span><span class="iconfont icon-guanbi"></span></li>';
// es6 insertAdjacentHTML 直接将字符串元素添加到父元素中
that.ul.insertAdjacentHTML('beforeend',li);
// 创建section标签
var section = '<section class="conactive">新建tab之'+num+'</section>';
that.fSection.insertAdjacentHTML('beforeend',section);
// 重置tab结构
that.init();
}
2.3.3 点击❌删除当前的tab项和内容项
- 实现步骤
- 获取❌元素对象
- 给❌绑定点击事件
- 点击处理事件中通过获取当前点击的❌的父节点,来间接移除li标签
- 如果移除的标签为当前选中状态,则移除之后设置前一个标签为默认选中态
- 如果移除的标签不是当前选中状态,则不进行第4步
- 当li标签被移除完之后,不再进行任何操作
- 实现代码
// 删除当前的tab项和内容项
// 注意: e需要作为参数需要放置在最后
deleteTab(that,e) {
// 阻止父元素切换事件
e.stopPropagation();
// 获取父元素的Index
var index = this.parentNode.index;
// 移除tab标签以及内容项
that.lis[index].remove();
that.sections[index].remove();
// 重置tab结构
that.init();
// 如果有选中项 则不进行默认选中设置
if (that.tabBox.querySelector('.liactive')) return;
// 没有选中项 设置前一个为默认的选中项
index--;
that.lis[index] && that.lis[index].click();
}
2.3.4 双击tab项文字或者内容项文字,修改里面的文字内容
- 实现步骤
- 获取当前双击元素对象
- 给当前元素对象绑定ondblclick双击事件
- 事件处理中,为当前元素对象添加Input标签元素,并将当前元素内容赋值给Input标签的value属性,最后为input标签设置默认选中状态
- 由于双击文字,会默认选定文字,此时需要双击禁止选中文字
window.getSelection()?window.getSelection().removeAllRanges():document.selection.empty();
- 当失去焦点或者按回车键时,将移除input标签,并将input标签中的内容设置为li标签的内容
- 实现代码
// 双击tab项文字或者内容项文字,修改里面的文字内容
editTab() {
// 获取当前选中元素对象
var _that = this;
// 禁止默认选中文字
window.getSelection()?window.getSelection().removeAllRanges():document.selection.empty();
// 获取当前元素文本内容
var content = this.innerHTML;
// 添加input节点
this.innerHTML = ‘’;
// 设置Input标签vlaue值 以及默认被选中
var input = this.children[0];
input.value = content;
input.select();
// input标签失去焦点移除input标签
input.onblur = function () {
_that.innerHTML = this.value;
}
// 键盘事件移除input标签
input.onkeyup = function (e) {
// 如果是回车键
if (e.keyCode === 13) {
this.blur();
}
}
}
}
```
2.4 总体实现代码
window.addEventListener('load',function () {
// var that;
class Tab {
constructor(attr) {
// 获取当前调用实例对象
// that = this;
// 获取tab盒子
this.tabBox = document.querySelector(attr);
// 获取➕元素对象
this.add = this.tabBox.querySelector('.tabadd');
// 获取ul
this.ul = this.tabBox.querySelector('.fisrstnav ul:first-child');
// 获取section盒子
this.fSection = this.tabBox.querySelector('.tabscon');
// 页面加载初始化绑定事件
this.init();
}
// 为每个标签初始化绑定事件绑定事件
init() {
// 获取目标对象
this.updateElement();
// 给➕绑定点击事件
this.add.onclick = this.addTab.bind(this.add,this); // 将全局当前函数的this指向改为全局this
// this指向当前Tab实例
// 给tab标签下的Li标签绑定点击事件并添加自定义属性
for (var i = 0; i < this.lis.length; i++) {
// 给li标签添加自定义属性
this.lis[i].index = i;
// this.toggleTab不加括号,只有当点击之后再调用
this.lis[i].onclick = this.toggleTab.bind(this.lis[i],this); // 并没有改变当前函数的this指向,只是将当前函数的this指向指回当前点击对象,并将全局this作为参数传入,避免定义全局this(that)
// 给❌绑定点击事件
this.delete[i].onclick = this.deleteTab.bind(this.delete[i],this);
// 给span标签绑定双击事件
this.spans[i].ondblclick = this.editTab;
// 给section绑定双击事件
this.sections[i].ondblclick = this.editTab;
}
}
updateElement() {
// 获取所有的li标签
this.lis = this.tabBox.querySelectorAll('li');
// 获取所有的section标签
this.sections = this.tabBox.querySelectorAll('section');
// 获取❌元素对象
this.delete = this.tabBox.querySelectorAll('.icon-guanbi');
// 获取所有的li标签里面的span
this.spans = this.tabBox.querySelectorAll('.fisrstnav ul li span:first-child');
}
// 清除li标签和section标签所有的选中类
clear() {
for (var i = 0; i < this.lis.length; i++) {
this.lis[i].className = '';
this.sections[i].className = '';
}
}
// tab栏切换 这里的this 指向调用者 即当前点击li标签
toggleTab(that) {
// 先清除已选中类 由于this指向li标签 因此需要用全局that调用实例对象获取当前实例对象的方法clear
that.clear();
// 为当前点击的Li标签添加liactive
this.className = 'liactive';
// 为对应的section标签添加选中类conactive
that.sections[this.index].className = 'conactive';
}
// 添加tab项和内容项
addTab(that) {
// 清除默认样式
that.clear();
var num = Math.floor(Math.random() * 20);
// 创建li标签
var li = '<li class="liactive"><span>新建tab页</span><span class="iconfont icon-guanbi"></span></li>';
// es6 insertAdjacentHTML 直接将字符串元素添加到父元素中
that.ul.insertAdjacentHTML('beforeend',li);
// 创建section标签
var section = '<section class="conactive">新建tab之'+num+'</section>';
that.fSection.insertAdjacentHTML('beforeend',section);
// 重置tab结构
that.init();
}
// 删除当前的tab项和内容项
// 注意: e需要作为参数需要放置在最后
deleteTab(that,e) {
// 阻止父元素切换事件
e.stopPropagation();
// 获取父元素的Index
var index = this.parentNode.index;
// 移除tab标签以及内容项
that.lis[index].remove();
that.sections[index].remove();
// 重置tab结构
that.init();
// 如果有选中项 则不进行默认选中设置
if (that.tabBox.querySelector('.liactive')) return;
// 没有选中项 设置前一个为默认的选中项
index--;
that.lis[index] && that.lis[index].click();
}
// 双击tab项文字或者内容项文字,修改里面的文字内容
editTab() {
// 获取当前选中元素对象
var _that = this;
// 禁止默认选中文字
window.getSelection()?window.getSelection().removeAllRanges():document.selection.empty();
// 获取当前元素文本内容
var content = this.innerHTML;
// 添加input节点
this.innerHTML = '<input type="text" />';
// 设置Input标签vlaue值 以及默认被选中
var input = this.children[0];
input.value = content;
input.select();
// input标签失去焦点移除input标签
input.onblur = function () {
_that.innerHTML = this.value;
}
// 键盘事件移除input标签
input.onkeyup = function (e) {
// 如果是回车键
if (e.keyCode === 13) {
this.blur();
}
}
}
}
new Tab('#tab');
})