zoukankan      html  css  js  c++  java
  • 227 面向对象版tab 栏切换

    3.1 功能需求

    1. 点击 tab栏,可以切换效果.
    2. 点击 + 号, 可以添加 tab 项和内容项.
    3. 点击 x 号, 可以删除当前的tab项和内容项.
    4. 双击tab项文字或者内容项文字可以修改里面的文字内容

    3.2 案例准备

    1. 获取到标题元素
    2. 获取到内容元素
    3. 获取到删除的小按钮 x号
    4. 新建js文件,定义类,添加需要的属性方法(切换,删除,增加,修改)
    5. 时刻注意this的指向问题

    3.3 切换

    • 为获取到的标题绑定点击事件,展示对应的内容区域,存储对应的索引

       this.lis[i].index = i;
       this.lis[i].onclick = this.toggleTab;
      
    • 使用排他,实现只有一个元素的显示

       toggleTab() {
         //将所有的标题与内容类样式全部移除
           for (var i = 0; i < this.lis.length; i++) {
           this.lis[i].className = '';
           this.sections[i].className = '';
           }
         //为当前的标题添加激活样式
           this.className = 'liactive';
          //为当前的内容添加激活样式
           that.sections[this.index].className = 'conactive';
        }
      

    3.4 添加

    • 为添加按钮+ 绑定点击事件

       this.add.onclick = this.addTab;
      
    • 实现标题与内容的添加,做好排他处理

      addTab() {
          that.clearClass();
          // (1) 创建li元素和section元素 
          var random = Math.random();
          var li = '<li class="liactive"><span>新选项卡</span><span class="iconfont icon-guanbi">				</span></li>';
          var section = '<section class="conactive">测试 ' + random + '</section>';
          // (2) 把这两个元素追加到对应的父元素里面
          that.ul.insertAdjacentHTML('beforeend', li);
          that.fsection.insertAdjacentHTML('beforeend', section);
          that.init();
          }
      

    3.5 删除

    • 为元素的删除按钮x绑定点击事件

       this.remove[i].onclick = this.removeTab;
      
    • 获取到点击的删除按钮的所在的父元素的所有,删除对应的标题与内容

       removeTab(e) {
           e.stopPropagation(); // 阻止冒泡 防止触发li 的切换点击事件
           var index = this.parentNode.index;
           console.log(index);
           // 根据索引号删除对应的li 和section   remove()方法可以直接删除指定的元素
           that.lis[index].remove();
           that.sections[index].remove();
           that.init();
           // 当我们删除的不是选中状态的li 的时候,原来的选中状态li保持不变
           if (document.querySelector('.liactive')) return;
           // 当我们删除了选中状态的这个li 的时候, 让它的前一个li 处于选定状态
           index--;
           // 手动调用我们的点击事件  不需要鼠标触发
           that.lis[index] && that.lis[index].click();
       }
      

    3.6 编辑

    • 为元素(标题与内容)绑定双击事件

       this.spans[i].ondblclick = this.editTab;
       this.sections[i].ondblclick = this.editTab;
      
    • 在双击事件处理文本选中状态,修改内部DOM节点,实现新旧value值的传递

      editTab() {
          var str = this.innerHTML;
          // 双击禁止选定文字
          window.getSelection ? window.getSelection().removeAllRanges() : 				    document.selection.empty();
          // alert(11);
            this.innerHTML = '<input type="text" />';
            var input = this.children[0];
            input.value = str;
            input.select(); // 文本框里面的文字处于选定状态
            // 当我们离开文本框就把文本框里面的值给span 
            input.onblur = function() {
            this.parentNode.innerHTML = this.value;
            };
            // 按下回车也可以把文本框里面的值给span
            input.onkeyup = function(e) {
            if (e.keyCode === 13) {
            // 手动调用表单失去焦点事件  不需要鼠标离开操作
            this.blur();
            }
          }
      }
      

    3.7 完整代码

    <!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/tab.js"></script>
    </body>
    
    </html>
    
    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";
    }
    
    tab.css代码
    
    * {
        margin: 0;
        padding: 0;
    }
    
    ul li {
        list-style: none;
    }
    
    main {
         960px;
        height: 500px;
        border-radius: 10px;
        margin: 50px auto;
    }
    
    main h4 {
        height: 100px;
        line-height: 100px;
        text-align: center;
    }
    
    .tabsbox {
         900px;
        margin: 0 auto;
        height: 400px;
        border: 1px solid lightsalmon;
        position: relative;
    }
    
    nav ul {
        overflow: hidden;
    }
    
    nav ul li {
        float: left;
         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 {
         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;
        /*  100px; */
        top: 0;
        right: 0;
    }
    
    .tabadd span {
        display: block;
         20px;
        height: 20px;
        line-height: 20px;
        text-align: center;
        border: 1px solid #ccc;
        float: right;
        margin: 10px;
        user-select: none;
    }
    
    .tabscon {
         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;
         100%;
        height: 100%;
    }
    
    .tabscon section.conactive {
        display: block;
    }
    
    tab.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('.fisrstnav ul:first-child');
            // 下面两行代码如果写这里,就是是页面一加载就获取的元素,动态添加的li、section元素是没有获取过来的,没获取过来的元素就不会绑定对应的事件。当点击 加号+按钮 的时候,要重新获取所有的li、section元素
            // this.lis = this.main.querySelectorAll('li');
            // this.sections = this.main.querySelectorAll('section');
            // section 父元素
            this.fsection = this.main.querySelector('.tabscon');
            this.init();
        }
    
        init() {
            this.updateNode();
            // init 初始化操作让相关的元素绑定事件
            this.add.onclick = this.addTab;
            for (var i = 0; i < this.lis.length; i++) {
                this.lis[i].index = i;
                this.lis[i].onclick = this.toggleTab;
                this.remove[i].onclick = this.removeTab;
                this.spans[i].ondblclick = this.editTab;
                this.sections[i].ondblclick = this.editTab;
            }
        }
    
        // 因为我们动态添加元素 需要从新获取对应的元素。【当点击加号+按钮的时候,要重新获取所有的li、section元素。】
        updateNode() {
            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() {
            // 注意,toggleTab里的this指向当前点击的li。
            // console.log(this.index);
            that.clearClass();
            this.className = 'liactive';
            that.sections[this.index].className = 'conactive';
        }
    
        // 清除所有li 和section 的类
        clearClass() {
            for (var i = 0; i < this.lis.length; i++) {
                this.lis[i].className = '';
                this.sections[i].className = '';
            }
        }
    
        // 2. 添加功能
        addTab() {
            that.clearClass();
            // (1) 创建li元素和section元素 
            var random = Math.random();
            var li = '<li class="liactive"><span>新选项卡</span><span class="iconfont icon-guanbi"></span></li>';
            var section = '<section class="conactive">测试 ' + random + '</section>';
            // (2) 把这两个元素追加到对应的父元素里面
            that.ul.insertAdjacentHTML('beforeend', li);
            that.fsection.insertAdjacentHTML('beforeend', section);
            that.init();
        }
    
        // 3. 删除功能
        removeTab(e) {
            e.stopPropagation(); // 阻止冒泡 防止触发li 的切换点击事件
            var index = this.parentNode.index;
            console.log(index);
            // 根据索引号删除对应的li 和section   remove()方法可以直接删除指定的元素
            that.lis[index].remove();
            that.sections[index].remove();
            that.init();
            // 当我们删除的不是选中状态的li 的时候,原来的选中状态li保持不变
            // 【删除后,如果有li处于选中状态,就return,不执行后面的代码。】
            if (document.querySelector('.liactive')) return;
            // 当我们删除了选中状态的这个li 的时候, 让它的前一个li 处于选定状态
            index--;
            // 手动调用我们的点击事件  不需要鼠标触发
            that.lis[index] && that.lis[index].click();
        }
    
        // 4. 修改功能
        editTab() {
            var str = this.innerHTML;
            // 双击禁止选定文字
            window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
            // alert(11);
            this.innerHTML = '<input type="text" />';
            var input = this.children[0];
            input.value = str;
            input.select(); // 文本框里面的文字处于选定状态
            // 当我们离开文本框就把文本框里面的值给span 
            input.onblur = function() {
                this.parentNode.innerHTML = this.value;
            };
            // 按下回车也可以把文本框里面的值给span
            input.onkeyup = function(e) {
                if (e.keyCode === 13) {
                    // 手动调用表单失去焦点事件  不需要鼠标离开操作
                    this.blur();
                }
            }
        }
    
    }
    new Tab('#tab');
    

  • 相关阅读:
    一行代码搞定Dubbo接口调用
    测试周期内测试进度报告规范
    jq 一个强悍的json格式化查看工具
    浅析Docker容器的应用场景
    HDU 4432 Sum of divisors (水题,进制转换)
    HDU 4431 Mahjong (DFS,暴力枚举,剪枝)
    CodeForces 589B Layer Cake (暴力)
    CodeForces 589J Cleaner Robot (DFS,或BFS)
    CodeForces 589I Lottery (暴力,水题)
    CodeForces 589D Boulevard (数学,相遇)
  • 原文地址:https://www.cnblogs.com/jianjie/p/12217210.html
Copyright © 2011-2022 走看看