javascript面向对象编程练习------tab栏

本文用JavaScript面向对象思想写tab栏

本文旨在对JavaScript面向对象加深印象,练习下思路

本文核心知识点:

  1. JavaScript面向对象的思想
  2. 面向对象中this指向问题

1. 功能需求

  1. 点击 tab栏,可以切换效果.
  2. 点击 + 号, 可以添加 tab 项和内容项.
  3. 点击 x 号, 可以删除当前的tab项和内容项.
  4. 双击tab项文字或者内容项文字可以修改里面的文字内容
  5. 细节处做优化(避免tab填满溢出,删完报错等)

2.效果预览

在这里插入图片描述

3.demo准备

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

4.功能完善

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

  • 使用排他,实现只有一个元素的显示

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

  • 实现标题与内容的添加,做好排他处理

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

  • 获取到点击的删除按钮的所在的父元素的所有,删除对应的标题与内容

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

  • 在双击事件处理文本选中状态,修改内部DOM节点,实现新旧value值的传递

4.5.处理细节
  • 对于代码进行适当优化
  • 细小问题及时发现并处理

完整js代码(注释超清晰)

window.addEventListener('load', function() {
    // 定义变量改变this指向
    var that;
    // 创建类(tab)
    class Tab {
        constructor(id) {
            that = this;
            // 获取元素
            this.main = document.querySelector(id);
            this.addBtn = this.main.querySelector('.tabadd');
            this.ul = this.main.querySelector('.fisrstnav ul');
            this.tabscon = this.main.querySelector('.tabscon');
            this.init();
        }

        // 初始化操作,每次刷新重新渲染
        init() {
            // 加载动态生成的元素
            this.updataNode();
            // 点击添加
            this.addBtn.onclick = this.add;
            // 给每个li绑定点击事件
            for (var i = 0; i < this.lis.length; i++) {
                // 为每个li绑定索引,后续操作便捷
                this.lis[i].index = i;
                this.lis[i].onclick = this.toggleTab;
                this.removeBtns[i].onclick = this.remove;
                this.spans[i].ondblclick = this.edit;
                this.sections[i].ondblclick = this.edit;
            }
        }

        // 用于重新加载那些动态生成的元素
        updataNode() {
            this.lis = this.main.querySelectorAll('li');
            this.sections = this.main.querySelectorAll('section');
            this.removeBtns = this.main.querySelectorAll('.iconfont');
            this.spans = this.main.querySelectorAll('.fisrstnav li span:first-child');
        }

        // 清除之前的类(样式)
        clearClass() {
            for (var i = 0; i < this.lis.length; i++) {
                this.lis[i].className = '';
                this.sections[i].className = '';
            }

        }

        // tab栏切换
        toggleTab() {
            // 先删除所有样式
            that.clearClass();
            // 当前点击添加样式
            this.className = 'liactive';
            that.sections[this.index].className = 'conactive';
        }

        // 添加功能
        add() {
            var ulWidth = this.parentNode.offsetWidth;
            // 清除所有样式,留自己
            that.clearClass();
            // 生成随机数,分配给内容
            var random = Math.random();
            // 创建新选项卡及内容并追加
            var li = '<li class="liactive"><span>newTab</span><span class="iconfont icon-guanbi"></span></li>';
            var section = '<section class="conactive">测试' + random + '</section>';
            // 判断大盒子宽度,限制增加个数
            // 每个li的宽度(兼容性高的写法)
            // console.log(this.parentNode.children[0].children[0].offsetWidth);
            var liWidth = this.previousElementSibling.children[0].offsetWidth;
            if (liWidth * that.lis.length < ulWidth - liWidth) {
                that.ul.insertAdjacentHTML('beforeend', li);
                that.tabscon.insertAdjacentHTML('beforeend', section);
            } else {
                alert('选项卡已达上限')
            }
            // 重新初始化,加载动态生成的元素
            that.init();
        }

        // 删除功能
        remove(e) {
            // 阻止冒泡,防止点击影响li的样式
            e.stopPropagation();
            // 点击删除图标拿到当前li及模块的索引
            var index = this.parentNode.index;
            // 根据索引删除对应的li及模块
            that.lis[index].remove();
            // that.sections[index].remove();(复习removeChild方法)
            that.tabscon.removeChild(that.sections[index]);
            // 删除后让此li前面的li添加选中样式(手动触发浅表的li点击事件)
            // 如果我们删除了非选定状态的li,之前选定状态不变
            if (document.querySelector('.liactive')) return;
            // 否则index进行自减
            index--;
            // 防止index < 0(做判断)
            that.lis[index] && that.lis[index].click();
            // 删除后重新渲染元素,保持元素动态变换
            that.init();
        }

        // 修改功能
        edit() {
            // 双击禁止选定文字
            window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
            // 获取当前span内的内容
            var str = this.innerHTML;
            // 改变点击的span的内部元素并传入value
            this.innerHTML = '<input type="text" value=' + str + '>';
            // 获得这个input
            var input = this.children[0];
            // 让input内容被选中
            input.select();
            // 当失去焦点,内容修改成功,内容给span
            input.onblur = function() {
                // 判断输入内容是否为空
                // if (this.value.trim().length == 0) {
                //     alert('tab不能为空')
                // } else {
                //     this.parentNode.innerHTML = this.value;
                // }
                this.value.trim().length == 0 ? alert('tab不能为空') : this.parentNode.innerHTML = this.value;
            };
            // 如果敲击回车,也可修改内容
            input.onkeyup = function(e) {
                if (e.keyCode === 13) {
                    // 手动触发失去焦点事件
                    this.blur()
                }
            }
        }
    }

    // 实例化对象
    new Tab("#tab")
})

最后:html及css部分在下惭愧,拿不出手,相信大家写的会比我好,奥利给。

猜你喜欢

转载自blog.csdn.net/cwq521o/article/details/106578505