【JavaScript系列六】—讲述JS学习历程的知识分享!

前言

本篇主要讲述了面向对象开发的特点,对象和类的概念与区别,包括详细讲解一个Tab选项卡案例

一、面向对象

在引出面向对象之前,我们首先要了解面向过程的概念

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个一个的依次调用就可以了

  • 优点:性能比面向对象高,适合跟硬件联系很紧密的东西,例如单片机就采用的面向过程编程
  • 缺点:不易维护、不易复用、不易扩展

面向对象就是把事务分解成为一个个对象,然后由对象之间分工与合作。倾向于以功能来划分问题,而不是步骤

  • 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统 更加灵活、更加易于维护
  • 缺点:性能比面向过程低

面向对象的三大特性

封装        继承        多态

对三大特性有兴趣的可以详细搜索了解~

二、对象和类

对象

  • 现实生活中的对象指的是一个具体的事物

  • JS 中的对象是由属性和方法组成的,是一个无序键值对的集合

  • 在 ES6 中新增加了类的概念,可以使用 class 关键字声明一个类,之后以这个类来实例化对象

  • 类抽象了对象的公共部分,它泛指某一大类(class)对象特指某一个,通过类实例化一个具体的对象

基本使用(代码)

class Star {
    constructor(uname, age) {
        // 通过 new 命令生成对象实例时自动调用该方法
        this.uname = uname;
        this.age = age;
    }
    sing(s) {
        return s;
    }
}
var zjl = new Star('周杰伦', 18);
console.log(zjl.uname, zjl.age, zjl.sing('花海'));

类的继承

核心就是extends关键字

class Father {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    sum() {
        console.log(this.x + this.y);
    }
    money() {
        console.log(100);
    }
}
class Son extends Father {
    constructor(x, y) {
        // super 可以访问或调用父类上的函数
        // 这里相当于调用了父类的 constructor
        super(x, y);
    }
}
var s = new Son();
s.money(); // 100

var s2 = new Son(3, 4);
s2.sum();

继承,子类没有自己的特殊属性的话不必写 constructor

super()的使用

调用父类的普通函数

class Father {
    say() {
        return 'hello';
    }
}
class Son extends Father{
    // 调用父类的普通函数
    say() {
        return super.say() + ' world';
    }
}
var s = new Son();
console.log(s.say()); // hello world

必须放在子类的this之前

class Father {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    sum() {
        return this.x + this.y + this.z;
    }
}
class Son extends Father{
    constructor(x, y, z) {
        // 先 super
        super(x, y);
        // 再 this
        this.z = z;
    }
}
var s = new Son(5, 3, 2);
console.log(s.sum()); // 10

注意

  • 先定义再使用

  • 类里面共有的属性或方法使用时要带 this

  • 类里面的 this 指向问题

  • constructor中的this指向实例对象

  • 方法里面的this指向方法的调用者

三、Tab选项卡案例详解

我们使用今日新知识运用,选项卡的基本功能包括切换、新增、修改、删除。

constructor 中获取元素,init 中绑定了事件相关的操作

切换功能

用到了 toggleTab,clearClass

var that;

class Tab {
    constructor(id) {
        that = this;
        this.main = document.querySelector(id);
        this.lis = this.main.querySelectorAll('li');
        this.sections = this.main.querySelectorAll('section');

        this.init();
    }
    init() {
        for(var i = 0; i < this.lis.length; i ++) {
            this.lis[i].index = i;
            this.lis[i].onclick = this.toggleTab;
        }
    }
    // 1. 切换
    toggleTab() {
        // 清除所有
        that.clearClass();
        // 激活自己
        this.className = 'liactive';
        that.sections[this.index].className = 'conactive';
    }
    clearClass() {
        for(var i = 0; i < this.lis.length; i ++) {
            this.lis[i].className = '';
            this.sections[i].className = '';
        }
    }
}

new Tab('#tab');

新增功能

  • 创建 li 和 icon,追加到对应父元素的后面,默认是激活的,所以添加之前要先进行 clearClass()
  • 解决持续添加有多个选项激活和新增的选项卡没有切换功能的问题。添加完之后调用 updateNode()重新获取 li 和 icon,并重新绑定事件,即调用 init()
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');
        // section 父
        this.fsection = this.main.querySelector('.tabscon');
        this.init();
    }
    init() {
        this.updateNode();
        // 切换~
        for(var i = 0; i < this.lis.length; i ++) {
            this.lis[i].index = i;
            this.lis[i].onclick = this.toggleTab;
        }
        // 添加~
        this.add.onclick = this.addTab;
    }
    updateNode() {
        this.lis = this.main.querySelectorAll('li');
        this.sections = this.main.querySelectorAll('section');
    }
    // 1. 切换
    toggleTab() {
        // 清除所有
        that.clearClass();
        // 激活自己
        this.className = 'liactive';
        that.sections[this.index].className = 'conactive';
    }
    clearClass() {
        for(var i = 0; i < this.lis.length; i ++) {
            this.lis[i].className = '';
            this.sections[i].className = '';
        }
    }
    // 2. 添加
    addTab() {
        that.clearClass();

        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>'; 
        that.ul.insertAdjacentHTML('beforeend', li);
        that.fsection.insertAdjacentHTML('beforeend', section);

        that.init();
    }
}

new Tab('#tab');

修改功能

  • 双击tab项文字或者内容项文字,可以修改里面的文字内容
  • 双击 span,存储下当前里面的内容

  • 往 span 中增加 input,并加 input 的 value 赋值为上面存储下来的值

  • 使 input 处于激活状态,input.select()

  • 离开 input 时,再把 input 的 value 赋值为 span 的 innerHTML

  • 修改功能比较简单,此处就不写代码了

删除功能

  • 删除后也最好调用 init() 重新更新下元素个数

  • 若删除的是选中的选项,让前一个高亮

  • 若删除的是没选中的选项,无需操作click()
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');
        // section 父
        this.fsection = this.main.querySelector('.tabscon');
        this.init();
    }
    init() {
        this.updateNode();
        // 切换~
        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.add.onclick = this.addTab;
    }
    updateNode() {
        this.lis = this.main.querySelectorAll('li');
        this.sections = this.main.querySelectorAll('section');
        this.remove = this.main.querySelectorAll('.icon-guanbi');
    }
    // 1. 切换
    toggleTab() {
        // 清除所有
        that.clearClass();
        // 激活自己
        this.className = 'liactive';
        that.sections[this.index].className = 'conactive';
    }
    clearClass() {
        for(var i = 0; i < this.lis.length; i ++) {
            this.lis[i].className = '';
            this.sections[i].className = '';
        }
    }
    // 2. 添加
    addTab() {
        that.clearClass();

        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>'; 
        that.ul.insertAdjacentHTML('beforeend', li);
        that.fsection.insertAdjacentHTML('beforeend', section);

        that.init();
    }
    removeTab(e) {
        var index = this.parentNode.index;

        that.lis[index].remove();
        that.sections[index].remove();

        e.stopPropagation();
        // init 放 index--前后都没关系,init 只会影响 li 的length
        // 而 index 是当前点击元素的索引,当前点击的元素还是那一个,放前放后并不会对此产生影响
        that.init();

        if(document.querySelector('.liactive')) return;
        index--;
        that.lis[index] && that.lis[index].click();
    }
}

new Tab('#tab');

有不明白的或者有其他问题的可以评论区留言噢

私信回复JS思维导图可获取完整知识导图~

今天的知识分享就到这里啦~希望大家在这能学到知识一起分享一起进步,成为更好的自己!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Star Universe

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

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

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

打赏作者

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

抵扣说明:

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

余额充值