文章目录
一、什么是面向对象:
1. 两大编程思想:
- 面向过程:
- 面向对象:
2. 面向过程编程(POP)
面向过程就是分析出解决问题所需要的步骤, 然后用函数把这些步骤一步步实现, 使用的时候再一个接一个依次调用就可以了.
3. 面向对象编程(OOP):
面向对象是把事物分解成一个个对象, 然后由对象之间分工合作;
面向对象程序开发思想中,每个对象都是功能中心, 具有明确的分工;
面向对象编程具有灵活,代码复用,容易维护和开发的有点;
面向对象的特性:
- 封装;
- 继承;
- 多态;
二、ES6中的类和对象:
1. 面向对象的思维特点:
- 抽取(抽象)对象公用的属性和行为组织(封装)成一个类;
- 对类进行实例化, 获取类的对象;
2. 对象:
- 具体的特指;
- 在js中, 对象是一组无序的相关属性和方法的集合, 所有事物都是对象;
- 对象是由属性和方法组成的:
- 属性: 事物的特性, 在对象中用属性来表示(常用名词);
- 方法: 事物的行为, 在对象中用方法来表示(常用动词)
3. 类: class
- 抽象的泛指;
- 在ES6中新增了类的概念, 使用class关键字声明一个类, 之后以这个类来实例化对象;
4. 创建类:
4.1 语法:
class name {
// class body
}
var xx = new name
注意:
- 类必须使用new来实例化;
4.2 类constructor 构造方法:
- constructor()方法是类的构造方法(默认方法), 用于传递参数, 返回实例对象, 通过new 关键字生成对象实例, 自动调用该方法.如果没有显式定义, 类内部会自动创建constructor();
class Start {
constructor(uname, age) {
// 构造方法
this.uname = uname;
this.age = age;
}
}
var ldh = new Start('刘德华', 18)
console.log(ldh); // {uname: "刘德华", age: 18}
console.log(ldh.uname); // 刘德华
console.log(ldh.age); // 18
4.3 类中添加方法:
class Start {
constructor(uname) {
this.uname = uname;
}
sing(song) {
console.log(this.uname + '在唱' + song)
}
}
var ldh = new Start('刘德华')
ldh.sing('冰雨') // 刘德华在唱冰雨
注意:
类中的方法不需要使用function定义
多个方法之间不需要添加分号(😉 或 逗号(,)分割;
4.4 类的继承:
// 父类
class Father {
constructor() {
this.money = 100;
}
have() {
console.log('这里有' + this.money + '元钱')
}
}
// 子类
class Soon extends Father{
}
// 实例化
var son = new Son()
son.have(); // 这里有100元钱
4.5 super:
super关键字用于访问和调用父类上的方法.可以d调用父类的构造方法, 也可以调用父类的普通方法;
注意:
- 子类在构造函数中使用super, 必须放在this前面(必须先调用父类构造方法, 再使用自己的构造方法)
// 父类
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
}
sum() {
return this.x + this.y;
}
say() {
console.log("我是父类")
}
}
// 子类
class Son extends Father{
constructor(x,y) {
super(x, y);
}
say() {
console.log("我是子类");
}
f_say() {
super.say();
}
}
// 实例化
var son = new Son(3, 4);
console.log(son.sum()); // 7
son.say(); // 我是子类
son.f_say() // 我是父类
5. ES6中类和对象:
三个注意点:
- 在ES6中类没有类型提升, 所以要先定义类, 再通过类实例化对象;
- 类里面使用公有的属性和方法一定要加this使用;
- 类里面this的指向问题;
- constructor: this指向的新创建的实例;
- 普通方法: this指向的是调用者;
三、案例: 面向对象的tab栏:
1. 功能需求:
- 点击tab栏, 可以实现切换效果;
- 点击+号, 可以添加tab项和内容项;
- 点击x号, 可以删除当前tab项和内容;
- 双击tab项文字或者内容项文字, 可以修改里面的内容
2. 思路:
抽象对象: Tab对象;
- 切换功能;
- 添加功能;
- 删除功能;
- 修改功能;
3. 知识整理:
3.1 向element添加元素: insertAdjacentHTML:
insertAdjacentHTML(‘位置’, “element-content”) 方法将指定的文本解析为 Element 元素,并将结果节点插入到DOM树中的指定位置。它不会重新解析它正在使用的元素,因此它不会破坏元素内的现有元素。这避免了额外的序列化步骤,使其比直接使用innerHTML操作更快.
语法:
element.insertAdjacentHTML(position, text);
- position:
位置参数 | 说明 |
---|---|
beforebegin | 元素自身的前面 |
afterbegin | 插入元素内部的第一个子节点之前 |
beforeend | 插入元素内部的最后一个子节点之后 |
afterend | 元素自身的后面 |
- text
是要被解析为HTML或XML元素,并插入到DOM树中的 DOMString;
3.2 禁用双击选中文字:
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
4. 代码实例:
<!DOCTYPE html>
<html lang="zh">
<head>
<title>面向对象的tab栏切换</title>
<link rel="stylesheet" href="./style.css">
<style>
* {
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: 80%; }
nav ul li span:last-child {
position: absolute;
user-select: none; /* 用户选择文本 */
font-size: 12px;
top: -18px;
right: 0;
display: inline-block;
height: 20px;
}
.tabadd {
position: absolute;
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;
}
.tabscon {
width: 100%;
height: 300px;
position: absolute;
padding: 30px;
top: 50px;
left: 0;
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; }
</style>
</head>
<body>
<main>
<h4>Js面向对象 动态添加标签页</h4>
<div class="tabsbox" id="tab">
<nav class="firstnav">
<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>
<script>
var that = null;
class Tab {
constructor(id) {
that = this;
// 获取元素
this.main = document.querySelector(id);
this.add = document.querySelector('.tabadd');
this.initTab();
}
initTab() {
this.lis = this.main.querySelectorAll('li');
this.sections = this.main.querySelectorAll('section');
this.removes = this.main.querySelectorAll('.icon-guanbi');
this.spans = this.main.querySelectorAll('.firstnav li span:first-child');
// 初始化操作
for(let i = 0; i < this.lis.length; i++) {
this.lis[i].index = i;
this.lis[i].onclick = this.toggleTab;
this.removes[i].onclick = this.removeTab;
this.spans[i].ondblclick = this.editTab;
this.sections[i].ondblclick = this.editTab;
}
this.add.onclick = this.addTab;
}
toggleTab() {
// 切换
that.clearClass(); // 注意指向问题
this.className = 'liactive';
that.sections[this.index].className = 'conactive';
}
addTab() {
that.clearClass();
// 添加
let _ul = document.querySelector('.firstnav ul:first-child');
let title = '新添加';
_ul.insertAdjacentHTML('beforeEnd', `<li class="liactive"><span>${title}</span><span class="iconfont icon-guanbi"></span></li>`);
let tabscon = document.querySelector('.tabscon ');
let content = '新添加的内容' + Math.random();
tabscon.insertAdjacentHTML('beforeEnd', `<section class="conactive">${content}</section>`);
// 重新加载l和section
that.initTab();
}
removeTab(e) {
// 删除
e.stopPropagation(); // 阻止冒泡
// 获取父级的索引号
let index = this.parentNode.index;
that.lis[index].remove();
that.sections[index].remove();
// 重新加载l和section
that.initTab();
if(document.querySelector('.liactive')) return;
// 当删除了选中状态的li
index--;
// 手动触发点击事件
that.lis[index] && that.lis[index].click();
}
editTab() {
// 修改功能
// 双击禁止选定文字
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
// 获取原内容
let str = this.innerHTML
this.innerHTML = `<input type='text'>`;
let input = this.children[0];
input.value = str;
input.select();
// 离开时赋值
input.onblur = function() {
this.parentNode.innerHTML = this.value;
}
// 按下回车提交修改
input.onkeyup = function(e) {
if(e.keyCode !== 13) return
this.blur();
}
}
clearClass() {
for(let i = 0; i < this.lis.length; i++) {
this.lis[i].className = '';
this.sections[i].className = '';
}
}
}
var tab = new Tab('#tab')
</script>
</body>
</html>