这是我的第一篇博客 博客生涯才开始 但是人生已经过去了二十个年头了 才开始弄这个 也没搞得太懂 我原本的想法是想搞个源代码上来 但是看了半天好像就只能传html源代码 那我还有css js的部分呢 我还想给大伙看看功能呢 其实我老早就想开个博客了 一直没找到在哪里来弄 学倒是一直在学 就这么学下来了 从html css h5c3 移动端适配 js基本语法 jQuery 到现在的js高级语法 es6 只不过前面好像也没什么需要讲的 现在才刚刚 开始 今天搞了个 面向对象版的tab栏 整点图片 上来把 我的话和经验也都在图片里 新手新手
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>面向对象 Tab</title> <link rel="stylesheet" href="./styles/tab.css"> <link rel="stylesheet" href="./styles/style.css"> </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> <script src="./js/index.js"></script> </body> </html>
// 分析 整个tab栏就是他的对象 然后下来有 切换 新增 删除 修改的内容 var that class Tab { constructor(id) { that = this // 1.获取元素 this.main = document.querySelector(id) /* // 2.切换功能 先获取li和section this.lis = this.main.querySelectorAll('.fisrstnav li') this.sections = this.main.querySelectorAll('section') */ // 3.新增功能 获取元素 this.add = this.main.querySelector('.tabadd') this.ul = this.main.querySelector('ul') this.fsections = this.main.querySelector('.tabscon') this.init() } // 3.5 获取最新的li和section updateTogle() { this.lis = this.main.querySelectorAll('.fisrstnav li') this.sections = this.main.querySelectorAll('section') // 4.获取删除按钮 由于这个也是也一直在动态增加的 所以需要动态获取 this.removes = this.main.querySelectorAll('.icon-guanbi') // 5.1动态获取第一个span的标签 this.spans = this.main.querySelectorAll('li span:first-child') } // 2.1初始化函数 因为页面一刷新就会要绑定事件 需要一实例化 就绑定事件 就要一个初始化函数在构造函数里被调用 init() { // 3.5获取最新数据 this.updateTogle() // 3.1新增按钮就一个 所以不需要写在循环里、 this.add.onclick = this.addTab // 2.2给lis绑定点击事件 for (var i = 0; i < this.lis.length; i++) { // 2.4要完成对应的section的切换 需要给每个li添加一个index this.lis[i].setAttribute('data-index', i) this.lis[i].onclick = this.toggleTab // 4.1删除按钮点击事件 this.removes[i].onclick = this.removeTab // 5.添加功能就是 对li section做操作 就不需要获取了 直接绑定双击事件 this.spans[i].ondblclick = this.insertTab this.sections[i].ondblclick = this.insertTab } } // 2.4 给其他事件清空类名操作 因为后面可能还会用到 封装一个函数 clearClass() { for (var i = 0; i < this.lis.length; i++) { this.lis[i].classList.remove('liactive') that.sections[i].classList.remove('conactive') } } // 切换 toggleTab() { that.clearClass() // 2.3在这里面完成切换功能 注意当前的this为点击的这个li this.classList.add('liactive') var index = this.getAttribute('data-index') // 注意 这个时候不能用this 要用controcutor里面的this that.sections[index].classList.add('conactive') } // 新增 addTab() { // 3.2点击新增就会增加一个li var li = '<li class="liactive"><span>新选项卡</span><span class="iconfont icon-guanbi"></span></li>' that.ul.insertAdjacentHTML('beforeend', li) // 3.3同时新增一个section var radom = Math.random() var section = '<section class="conactive">测试'+radom+'</section>' that.fsections.insertAdjacentHTML('beforeend', section) // 3.4因为新增过后就需要到新增的选项卡里面来 所以 就要重新清空类名 that.clearClass() // 3.5连续点多个新增 后面新增的全是选中状态的原因 新增一次过后就要重新执行一次初始化 获到最新的li和section that.init() } // 删除 removeTab(e) { e.stopPropagation() // 4.2点一次删除 就会把当前的父元素删掉 var index = this.parentNode.getAttribute('data-index') this.parentNode.remove() // 同时把section删掉 that.sections[index].remove() // 删除一个 应该跳转到前一个选项卡 // 疑难点:这里遇到了做下来的第一个困难点 我一看代码一直在寻思没什么没问题啊 但就是不能实现点击事件 后来才发现是因为此处有个冒泡事件 先执行了那个就点击在原地两个互相作用才出现了问题 关闭冒泡事件即可 // that.lis[index - 1].click() // 4.3删除到第一个会报错 这里可以利用与的短路运算 前面为true就执行后面 前面为false就执行前面 // that.lis[index - 1] && that.lis[index - 1].click() // 此处还是有点小瑕疵 就是当我点击选项一的时候 我去删除选项三 删完过后 它会自动跳到选项二 正常应该保持不动就可以 // 突然想到这里如果有jq的hasclass方法就舒服了 if (this.parentNode.classList[0] == 'liactive') { that.lis[index - 1] && that.lis[index - 1].click() } } // 修改 insertTab() { // 取消双选选中文字 window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty() // 5.1 双击过后把第一个span里的内容改为文本框 var str = this.innerHTML this.innerHTML = '<input type=“text”>' // 5.2变文本框之后应该把span的值给到文本框里面 this.children[0].value = str // 5.3失去焦点后 把input的值给到innerhtml -----------------------time--------------------------- this.children[0].onblur = function() { this.parentNode.innerHTML = this.value } } } new Tab('#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; }