js高级—tab栏切换(面向对象做法)

    <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>
        * {
    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: 0px;
    right: 0;
    display: inline-block;
    width: 20px;
    height: 20px;
    background-color: red;
    cursor: pointer;
}

.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;
    cursor: pointer;
}

.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;
}
<script type="text/javascript">
    //定义一个that变量,让实例对象中的this进行赋值
    var that;
    class Tab{
        constructor(id){
            //将实力对象中的this赋值到that中
            that = this;

            //首先获取最大父盒子的元素 , 此处的this指向实力对象
            //获取需要操作的标签
            this.main = document.querySelector(id);
            // //获取最大父盒子中的所有li
            // this.lis = this.main.querySelectorAll('li');
            // // 获取最大父盒子中的所有section
            // this.sections = this.main.querySelectorAll('section');

			/*动态创建li和section 可以将选择器更换为*/
            // //获取最大父盒子中的所有li
            // this.lis = this.main.getElementsByTagName('li');
            // // 获取最大父盒子中的所有section
            // this.sections = this.main.getElementsByTagName('section');

            // 因为getElementsByTagName具有隐式遍历的作用
	

            //获取最大父盒子中的tabadd
            this.add = this.main.querySelector('.tabadd');
            //获取最大父盒子中的fisrstnav下的第一个元素标签 (li的父元素)
            this.ul = this.main.querySelector('.fisrstnav ul:first-child');
            //获取最大父盒子中的tabscon的元素标签 (tabscon父元素)
            this.fsection = this.main.querySelector('.tabscon');
            // //获取最大盒子中的icon-guanbi
            // this.remove = this.main.querySelectorAll('.icon-guanbi')


            this.init();
        }
        //设置一个初始化的函数,让相关元素绑定事件(主要就是添加相关的绑定事件)
        init(){


            //一初始化的时候就调用新的li和section(重新调用切记写在最前面,要不然添加时,最后一个li没有效果)
            this.updateNode();




            //循环li,进行添加绑定事件,此处的长度设置为实例对象中的写法//this.lis.length
            for (var i = 0; i < this.lis.length; i++) {
                // 此处为了后期与section进行绑定,利用实力对象形式设置一个变量保存每次遍历的索引
                this.lis[i].index = i;
                //会给每个li设置点击事件
                //此处测试li是否已经可以点击,拿到索引号
                // this.lis[i].onclick = function(){
                //     console.log(this.index);
                    
                // }

                //每个li设置点击事件,触发toggleTab的函数效果
                this.lis[i].onclick = this.toggleTab;

                //给每个icon-guanbi按钮进行绑定事件
                this.remove[i].onclick = this.removeTab;

                //给每个span设置鼠标双击事件
                this.spans[i].ondblclick = this.editTab;
                
                //给每个sections绑定一个双击事件(此处因为所需要用到的方法跟span设置的事件方法一样,所以此处直接调用span的双击方法)
                this.sections[i].ondblclick = this.editTab;
            }

            //添加事件不需要进行遍历
            this.add.onclick = this.addTab;

            
        }

        //重新获取所有的小li和section
        updateNode(){
            //获取最大父盒子中的所有li
            this.lis = this.main.querySelectorAll('li');
            // 获取最大父盒子中的所有section
            this.sections = this.main.querySelectorAll('section');
            //获取最大盒子中的icon-guanbi
            this.remove = this.main.querySelectorAll('.icon-guanbi')
            //获取所有的li下的第一个span
            this.spans = this.main.querySelectorAll('.fisrstnav li span:first-child')
        }




/*****************************************************************************************************/ 
        //1.切换功能
        toggleTab(){
            //在此处调用清楚样式的函数,此处的this修改为that,因为this的话只能理解为li调用了此方法
            //其中还有sections的存在,因此用that进行包含
            that.clearClass();


            //测试li是否已经可以点击,拿到索引号
            // console.log(this.index);
            
            //此处的this指向的是li这个标签(谁调用了我,我就指向谁)
            this.className = 'liactive';
            //因为this指向的是li,li中没有conactive这个类名属性,所以this.sections[thsi.index] = 'conactive';
            // 不管用,因此可以得到此conactive为constructor(实例对象)中的元素
            // this.sections[thsi.index] = 'conactive';

            //设置一个全局变量taht,对实例对象中的this进行赋值,进行调用
            //因此此处的this,修改为that
            that.sections[this.index].className = 'conactive';  

        }
        //设置一个清楚样式的函数(清除所有li和section中的类)
        clearClass(){
            for (let i = 0; i < this.lis.length; i++) {
                //清除li和sections下的所有类(此处用到排他思想处理)
                this.lis[i].className = '';
                //此处sections可以用that或者this,在调用方法时用that就可以了
                that.sections[i].className = '';  
            }
        }
/*****************************************************************************************************/ 

        //2.添加功能
        addTab(){
            //进行排他思想,让创建的标签类达到比较好的效果
            that.clearClass();


            //绑定测试
            // alert(123)
            
            //为了生成的效果好看,添加个生成随机数
            var random = Math.random();

            //(1) 创建li元素和section元素
            var li = '<li class="liactive"><span>新选项卡</span><span class="iconfont icon-guanbi"></span></li>'
            var section = ' <section class="conactive">新内容'+ random +'</section>';
            //(2) 将以下的两个元素添加到父元素中(利用insertAdjacentHTML方法进行子元素的添加,因为insertAdjacentHTML不局限于文字添加,方法中的beforeend,是将标签等信息放在盒子里面的最后一个)
            //因为addTab指向的实例对对象,因此此处用that
            that.ul.insertAdjacentHTML('beforeend',li);
            that.fsection.insertAdjacentHTML('beforeend',section);

            //此处在重新调用一次init方法;
            that.init();
        }

        // 已经设置了 updateNode() 函数重新调用li和section的个数


/*****************************************************************************************************/ 
        //3.删除功能
        //给当前函数添加事件对象(事件参数),阻止事件冒泡行为
        removeTab(e){
            e.stopPropagation(); //利用事件参数阻止冒泡,防止出发li的点击事件
            //此时会出现新增li中的删除按钮跟当前索引取不到一起,因此将获取关闭按钮的元素放到 updateNode()方法中重新获取即可
            //引用父元素的索引号
            var index = this.parentNode.index;
            // 测试
            console.log(index);

            // remove() 方法则可以直接删除指定的元素
            that.lis[index].remove();
            that.sections[index].remove();
            //此处调用init方法,为了让init方法执行 updateNode() 方法,即可拿到新的元素进行遍历使用
            that.init();

            //当我们删除的不是选中状态的li的时候,原来的选中状态li保持不变
            //如果当前的标签存折liactive这个标签状态,就直接返回值,不必执行下面的代码
            if(document.querySelector('.liactive'))return;


            //当我们删除了选中状态的这个li的时候,让它的前一个li处于选定状态
            //让index--;从而让前一个li为选中状态
            index--;
            //index--;于此同时自动调用lis的点击事件,让sections也属于选中状态
            // that.lis[index].click();
            //利用 && 对前后的效果进行判断 (&& 与)
            that.lis[index] && that.lis[index].click();


            


        }

/*****************************************************************************************************/ 
        //4.修改功能
        editTab(){
            //先获取原来的文本文字
            var str = this.innerHTML;
            //双击禁止选定文字;
            window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty()
            //测试
            // alert(123)
            //使鼠标双击到的标签设置为文本标签
            this.innerHTML = '<input type="text" />';
            //获取input标签,将原来的文本文字赋值给input
            var input = this.children[0];
            input.value = str;
            //让文本框内的文字处于选定状态
            input.select();

            //当我们离开文本框,将文本框内的值设置给span
            input.onblur = function(){
               this.parentNode.innerHTML = this.value;
            };
            input.onkeyup = function(e){
                if(e.keyCode === 13){
                    //手动调用表单失去焦点事件 不需要鼠标离开操作
                this.blur();
                }   
            }
        }






    }

    //创建的实力对象必须存在实例函数的下面,不然执行结果为undeiful
    //首先过去最大的父盒子元素
   /*var a =  */ new Tab('#tab');
    // a.init();
  </script>

实现效果:

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑白两客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值