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 功能预览

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

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栏切换效果
  1. 实现步骤
    1. 获取所有的li标签
    2. 给每个li标签添加自定义属性
    3. 给每个li标签添加点击事件
    4. 点击处理函数中,为当前点击li标签添加选中状态class类liactive
  2. 实现代码
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项和内容项
  1. 实现步骤
    1. 获取➕元素对象
    2. 给➕元素对象绑定点击事件
    3. 点击处理事件通过insertAdjacentHTML 创建子tab项,以及内容项
  2. 实现代码
// 添加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项和内容项
  1. 实现步骤
    1. 获取❌元素对象
    2. 给❌绑定点击事件
    3. 点击处理事件中通过获取当前点击的❌的父节点,来间接移除li标签
    4. 如果移除的标签为当前选中状态,则移除之后设置前一个标签为默认选中态
    5. 如果移除的标签不是当前选中状态,则不进行第4步
    6. 当li标签被移除完之后,不再进行任何操作
  2. 实现代码

        // 删除当前的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项文字或者内容项文字,修改里面的文字内容
  1. 实现步骤
    1. 获取当前双击元素对象
    2. 给当前元素对象绑定ondblclick双击事件
    3. 事件处理中,为当前元素对象添加Input标签元素,并将当前元素内容赋值给Input标签的value属性,最后为input标签设置默认选中状态
    4. 由于双击文字,会默认选定文字,此时需要双击禁止选中文字
                window.getSelection()?window.getSelection().removeAllRanges():document.selection.empty();
    
    
    1. 当失去焦点或者按回车键时,将移除input标签,并将input标签中的内容设置为li标签的内容
  2. 实现代码

// 双击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');
})

猜你喜欢

转载自blog.csdn.net/chen__cheng/article/details/113479749