本文主要是对js面向对象和组件封装做一个简单的学习笔记;
1 Tab组件封装
1.1 面向过程
下面代码实现了一个简单的tab功能
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div class="tab1">
<button style="background: red">按钮一</button>
<button>按钮二</button>
<button>按钮三</button>
<p>内容一</p>
<p style="display: none">内容二</p>
<p style="display: none">内容三</p>
</div>
<div class="tab2">
<button style="background: red">按钮一</button>
<button>按钮二</button>
<button>按钮三</button>
<p>内容一</p>
<p style="display: none">内容二</p>
<p style="display: none">内容三</p>
</div>
<button class="nextPre">点我下一页</button>
<button class="autoPlay">点我第二个选项卡自动轮播</button>
</body>
<script type="text/javascript">
function Tab(btns, ps, isNextPre = false, isAutoPlay = false) {
btns.forEach((value, key) => {
value.onclick = function() {
psFor(key)
}
})
if(isNextPre) {
let num = 0;
document.querySelector('.nextPre').onclick = function() {
num++;
num = num > 2 ? 0 : num;
psFor(num);
}
}
if(isAutoPlay) {
document.querySelector('.autoPlay').onclick = function() {
let num = 0;
setInterval(() => {
num++;
num = num > 2 ? 0 : num;
psFor(num);
}, 1000)
}
}
function psFor(key) {
ps.forEach((v, k) => {
if(key === k) {
btns[k].style.background = 'red';
ps[k].style.display = 'block';
} else {
btns[k].style.background = '';
ps[k].style.display = 'none';
}
})
}
}
let btns = document.querySelectorAll(".tab1 button");
let ps = document.querySelectorAll(".tab1 p");
Tab(btns, ps, false, false);
let btns2 = document.querySelectorAll(".tab2 button");
let ps2 = document.querySelectorAll(".tab2 p");
Tab(btns2, ps2, true, true);
</script>
</html>
效果如下:
1.2 工厂模式
工厂模式简介,实现步骤如下:
function Tab() {
// 添加原料
let obj = {};
//加工原料
obj.tabLength = 1;
obj.psFor = function() {
console.log("psFor....");
}
// 出厂
return obj;
}
工厂模式问题:
对象识别问题:
// 缺点一:对象识别问题
let tab1 = Tab();
console.log(tab1.constructor);
// ƒ Object() { [native code] }
性能问题:
tab1.psFor();
let tab2 = Tab();
tab2.psFor();
// 缺点二:性能问题
console.log(tab1.psFor === tab2.psFor); // false
tab组件的工厂模式实现
<script type="text/javascript">
function Tab(btns, ps, isNextPre = false, isAutoPlay = false) {
btns.forEach((value, key) => {
value.onclick = function() {
psFor(key)
}
})
function psFor(key) {
ps.forEach((v, k) => {
if(key === k) {
btns[k].style.background = 'red';
ps[k].style.display = 'block';
} else {
btns[k].style.background = '';
ps[k].style.display = 'none';
}
})
}
let obj = {};
obj.psFor = psFor;
obj.eleLength = btns.length;
return obj;
}
let btns = document.querySelectorAll(".tab1 button");
let ps = document.querySelectorAll(".tab1 p");
let tab1 = Tab(btns, ps);
let num = 0;
document.querySelector('.nextPre').onclick = function() {
num++;
num = num > tab1.eleLength - 1 ? 0 : num;
tab1.psFor(num);
}
let btns2 = document.querySelectorAll(".tab2 button");
let ps2 = document.querySelectorAll(".tab2 p");
let tab2 = Tab(btns2, ps2);
document.querySelector('.autoPlay').onclick = function() {
let num2 = 0;
setInterval(() => {
num2++;
num2 = num2 > tab2.eleLength - 1 ? 0 : num2;
tab2.psFor(num2);
}, 1000)
}
</script>
1.3 构造函数模式
构造函数一般首字母大写, 属性放在构造函数里,方法放在原型
function Tab() {
this.name = '张三';
this.hobby = function() {
console.log('篮球');
}
}
Tab.prototype.psFor = function() {
console.log("psFor...");
}
Tab.prototype.hobby = function() {
console.log("hobby...");
}
let tab1 = new Tab();
console.log(tab1.name);
tab1.hobby();
let tab2 = new Tab();
console.log(tab1.psFor === tab2.psFor); // true
console.log(tab1.__proto__ === Tab.prototype); // true
// 每个原型上都有一个预定义属性:constructor --> 构造函数;
console.log(Tab.prototype.constructor === Tab) // true
console.log(tab1.constructor === Tab) // true
构造函数继承
继承:子类继承父类所有的属性和行为,父类不受影响
目的:找到类之间的共性精简代码
function Person(name) {
this.name = name;
this.eyes = '两只';
this.legs = '两条';
}
function Student(name) {
Person.call(this, name);
this.className = "二班"
}
let newPerson = new Student('张三');
console.log(newPerson.className);
// 简单原型继承,出现影响父类的情况
Student.prototype = Person.prototype; // 直接赋值
原型链继承
原型链是指对象在访问属性或者方法时的查找方式
当访问一个对象的属性或者方法时,会在对象自身上查找属性或方法是否存在,如果存在就使用自身的属性或方法,如果不存在就去创建对象的构造函数的原型对象中查找,依次类推,直到找到为止,如果到顶层对象中还找不到,则返回undefined
原型链最顶层为Object构造函数的prototype原型对象
function Dad(height) {
this.name = "张三";
this.age = 20;
this.heigth = height;
this.money = "$1000000";
}
Dad.prototype.hobby = function() {
console.log('喜欢高尔夫');
}
function Son(height) {
Dad.call(this, height);
}
// 原型链继承
let Link = function() {};
Link.prototype = Dad.prototype;
Son.prototype = new Link();
Son.prototype.constructor = Son;
Son.prototype.hobby = function() {
console.log('喜欢篮球');
}
let newSon = new Son("178cm");
// console.log(newSon);
newSon.hobby();
let newDad = new Dad("179cm");
newDad.hobby();
tab组件的构造函数实现
function Tab(btns, ps) {
this.btns = btns;
this.ps = ps;
this.btnFor();
}
Tab.prototype.btnFor = function() {
this.btns.forEach((value, key) => {
value.onclick = () => {
this.psFor(key)
}
})
}
Tab.prototype.psFor = function(key) {
this.ps.forEach((v, k) => {
if(key === k) {
this.btns[k].style.background = 'red';
this.ps[k].style.display = 'block';
} else {
this.btns[k].style.background = '';
this.ps[k].style.display = 'none';
}
})
}
let btns = document.querySelectorAll(".tab1 button");
let ps = document.querySelectorAll(".tab1 p");
let tab1 = new Tab(btns, ps);
let num = 0;
document.querySelector('.nextPre').onclick = function() {
num++;
num = num > tab1.btns.length - 1 ? 0 : num;
tab1.psFor(num);
}
let btns2 = document.querySelectorAll(".tab2 button");
let ps2 = document.querySelectorAll(".tab2 p");
let tab2 = new Tab(btns2, ps2);
document.querySelector('.autoPlay').onclick = function() {
let num2 = 0;
setInterval(() => {
num2++;
num2 = num2 > tab2.btns.length - 1 ? 0 : num2;
tab2.psFor(num2);
}, 1000)
}
2 Drag组件封装
下面代码实现了拖拽组件的封装
2.1 es5继承
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.mydiv1{
width: 100px;
height: 100px;
background: red;
position: absolute;
}
.mydiv2{
width: 100px;
height: 100px;
background: purple;
position: absolute;
left: 300px;
}
</style>
</head>
<body>
<div class="mydiv1"></div>
<div class="mydiv2"></div>
</body>
<script type="text/javascript">
// 面向对象
function Drag(ele) {
this.ele = ele;
this.downFn();
}
Drag.prototype.downFn = function() {
this.ele.onmousedown = e => {
let ev = e || window.event;
let x = ev.clientX - this.ele.offsetLeft;
let y = ev.clientY - this.ele.offsetTop;
this.moveFn(x, y);
this.upFn();
}
}
Drag.prototype.moveFn = function(x, y) {
this.ele.onmousemove = e => {
let ev = e || window.event;
let xx = ev.clientX;
let yy = ev.clientY;
this.setStyle(xx - x, yy - y);
}
}
Drag.prototype.setStyle = function(leftNum, topNum) {
this.ele.style.left = leftNum + "px";
this.ele.style.top = topNum + "px";
}
Drag.prototype.upFn = function() {
this.ele.onmouseup = () => {
this.ele.onmousemove = "";
}
}
let mydiv1 = document.querySelector(".mydiv1");
let drag1 = new Drag(mydiv1);
function LimitDrag(ele) {
Drag.call(this, ele);
}
// 通过中间函数切断子类与父类的原型链接
let Link = function() {};
Link.prototype = Drag.prototype;
LimitDrag.prototype = new Link();
// 此处也可以采用深拷贝继承
// LimitDrag.prototype = deepClone(Drag.prototype);
// 子类的constructor属性指回子类的构造函数
LimitDrag.prototype.constructor = LimitDrag;
LimitDrag.prototype.setStyle = function(leftNum, topNum) {
leftNum = leftNum < 0 ? 0 : leftNum;
topNum = topNum < 0 ? 0 : topNum;
this.ele.style.left = leftNum + "px";
this.ele.style.top = topNum + "px";
}
let mydiv2 = document.querySelector(".mydiv2");
let drag2 = new LimitDrag(mydiv2);
</script>
</html>
2.2 es6继承
父类拖拽组件
class Drag{
constructor(ele) {
this.ele = ele;
this.downFn();
}
downFn() {
this.ele.onmousedown = e => {
let ev = e || window.event;
let x = ev.clientX - this.ele.offsetLeft;
let y = ev.clientY - this.ele.offsetTop;
this.moveFn(x, y);
this.upFn();
}
}
moveFn(x, y) {
this.ele.onmousemove = e => {
let ev = e || window.event;
let xx = ev.clientX;
let yy = ev.clientY;
this.setStyle(xx - x, yy - y);
}
}
setStyle(leftNum, topNum) {
this.ele.style.left = leftNum + "px";
this.ele.style.top = topNum + "px";
}
upFn() {
this.ele.onmouseup = () => {
this.ele.onmousemove = "";
}
}
}
export default Drag;
子类
import Drag from './Drag.js'
class LimitDrag extends Drag {
constructor(ele) {
super(ele);
}
setStyle(leftNum, topNum) {
leftNum = leftNum < 0 ? 0 : leftNum;
topNum = topNum < 0 ? 0 : topNum;
// 通过super调用父类的方法
super.setStyle(leftNum, topNum)
}
}
export default LimitDrag;