前言
本篇主要讲述了面向对象开发的特点,对象和类的概念与区别,包括详细讲解一个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');
有不明白的或者有其他问题的可以评论区留言噢
今天的知识分享就到这里啦~希望大家在这能学到知识一起分享一起进步,成为更好的自己!
标签:index,JavaScript,JS,学习,init,lis,var,li,main From: https://blog.csdn.net/m0_60623820/article/details/141932534