欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-30 13:30:11
...
    <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');
            //获取最大父盒子中的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>

实现效果:

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

相关标签: 前端网页小项目