结构和源码在最后,
功能需求:
1.点击tab栏可以切换效果
2.点击+号,可以添加tab项和内容项
3.点击ⅹ号,可以删除当前的tab项和内容项
4.双击tab项文字或者内容项文字可以修改里面的文字内容
简单思路分析:
思路总结
1,一共有四个大的模块,分别是 1,切换 2,增加 3,删除 4,修改
首先constructor构造函数获取对象:id 增加模块 li的父元素, section的父元素
1,切换模块
切换模块是使用点击事件进行排他思想,将其余的li和对应的section的类名
清空,当前点击的添加类名
初始化操作使用for循环添加点击事件,同时给每一个li添加一个索引号方便一一对应,
2增加模块
同时增加li和section,先获取到 sections和它的父元素,
为了保证增加后的li有索引号,并且可以正常进行其他操作,
需要重新获取一次所有的li和section并进行事件添加和排他思想
因此单独使用一个 updataNode方法对li section remove span进行获取
获取之后进行初始化,在init方法中重新添加事件
3,删除模块
section需要在updataNode模块中获取,
然后再init初始化模块中给li里面x添加点击事件,事件处理程序为removeTab方法;
removeTab方法中 同时删除当前点击的li和拥有li对应index的section,然后
调用初始化方法init (用户体验优化,删除了带有类名的li后,自动给前一个li添加类名)
删除的如果是不带类名的,则不变
4,修改功能
核心思想:(先取消双击选中文字)添加双击事件,双击后给点击的li添加一个inpt框
先选中原li中的内容,然后将内容放到input框框中 ,使用select方法默认选中,
给input添加失去焦点事件 失去焦点时将内容给li(键盘回车)
html结构
<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>
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;/* z-index: 33333; */}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;}
JS代码
let that;class Tab {constructor(id) {this.main = document.querySelector(id);this.add = this.main.querySelector(\'.tabadd\');//li的父元素this.ul = this.main.querySelector(\'.fisrstnav ul:first-child\');this.fsection = this.main.querySelector(\'.tabscon\');this.init();}//init 初始化(新添加或者删除后可以更新)init() {this.updateNode(); //初始化li和section 重新添加点击事件this.add.onclick = this.addTab; //调用下面的添加方法addTabfor (let i = 0; i < this.lis.length; i++) {this.lis[i].index = i; //给所有li添加索引号this.lis[i].onclick = this.toggleTab; //给所有li添加点击事件this.lis[i].addEventListener(\'click\', this.toggleTab) //给所有li添加点击事件//给所有小X添加点击事件this.remove[i].onclick = this.removeTab;this.spans[i].ondblclick = this.editTab; //给所有li里面的span添加双击事件this.sections[i].ondblclick = this.editTab; //给所有li里面的span添加双击事件that = this;}}// 重新获取最新的 获取li和sectionupdateNode() {this.lis = this.main.querySelectorAll(\'li\');this.sections = this.main.querySelectorAll(\'section\');this.remove = this.main.querySelectorAll(\'.icon-guanbi\'); //获取关闭按钮this.spans = this.main.querySelectorAll(\'.fisrstnav li span:first-child\');}//1,切换toggleTab() {that.clearClass();this.className = \'liactive\'; //给当前的添加类名that.sections[this.index].className = \'conactive\' //对应的内容添加类名显示}clearClass() { //清除所有li和section其他类名函数for (let i = 0; i < this.lis.length; i++) {this.lis[i].className = \'\'; //清除其他lithis.sections[i].className = \'\'; //清除其他section}}//2,添加功能addTab() {that.clearClass();let random = Math.random();let li = `<li class=\"liactive\"><span>测试1</span><span class=\"iconfont icon-guanbi\"></span></li>`;let section = `<section class=\"conactive\">${random}</section>`;that.ul.insertAdjacentHTML(\'beforeend\', li);that.fsection.insertAdjacentHTML(\'beforeend\', section)that.init();}//3,删除功能removeTab(e) {e.stopPropagation(); //阻止冒泡let index = this.parentNode.index;that.lis[index].remove();that.sections[index].remove();that.init();if (document.querySelector(\'.liactive\')) return;index--;//如果有就 //手动调用点击事件that.lis[index] && that.lis[index].click();}//4,修改功能editTab() {let str = this.innerHTML; //先获取到文字//阻止双击选中文字;window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();this.innerHTML = `<input type=\"text\">`;let input = this.children[0]; //获取到input框input.value = str; //将获取到的文字给文本框input.select(); //让文字处于选中状态input.onblur = function () {this.parentNode.innerHTML = input.value;}input.onkeyup = function (e) { //回车设置内容给spanif (e.keyCode == 13) {input.blur();}}}}new Tab(\'#tab\')