js实现封装jQuery的简单方法与链式操作详解

时间:2022-01-17 15:50:48

我用这篇文章来理一理如何用js去实现封装jQuery的简单方法。

本文js实现了下面jquery的几种方法,我将它分为8个小目标

  • 实现$(".box1").click( )方法
  • 实现$("div").click( )方法
  • 考虑$( )中参数的三种情况
  • 实现jq中的on方法
  • 实现链式操作
  • 实现jq中的eq方法
  • 实现jq中的end方法
  • 实现jq中的css方法

有不正确的地方还望大家在评论区指出来,谢谢啦。

1. 实现$(".box1").click( )方法

首先,我们定第一个小目标,就是如何一步一步去实现下方jQuery代码的功能。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Document</title>
 //同一个文件下操作的话,后面记得删除下面引入的cdn
 <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
 <style> .box1 {
  width: 100px;
  height: 100px;
  background: red;
 } </style>
</head>
<body>
 <div class="box1"></div>
</body>
<script> $(".box1").click(()=>{
 console.log(456);
 }) </script>
</html>
复制代码
?
1
2
3
$(".box1").click(()=>{
console.log(456);
})

好了,言归正传,我们来分析上面jQuery的代码。

  • $(".box1") 就是实现了选择器的功能。
  • $(".box1").click 就是选择器 + 调用click方法
  • 最后在click里面传入函数。

第一个小目标就是自己封装js来实现上面代码的功能。我们分三步走战略来实现。

  1. js实现 $(".box1")
  2. 实现 $(".box1").click()
  3. 实现 $(".box1").click( ( ) => { console.log("123") } )

第一步就是先用js实现 $(".box1"), 对吧

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 实现$(".box1")
class jquery {
constructor(arg) {
 console.log(document.querySelector(arg));
}
}
 
function $(arg) {
return new jquery(arg);
}
 
// 实现$(".box1")
let res = $(".box1");
console.log(res);

这样是不是就通过构建()方法并返回jquery实例,实现了(".box1")呢。

那好,接下来我们进行第二步就是实现 $(".box1").click()。相信大家也看出来了,就是在jquery类中多了一个click方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 实现$(".box1").click()
class jquery {
constructor(arg) {
 console.log(document.querySelector(arg));
}
 
click() {
 console.log("执行了click方法");
}
}
 
function $(arg) {
return new jquery(arg);
}
 
// 实现$(".box1").click()
let res = $(".box1").click();
console.log(res);

接下来,我们进行第三步就是实现 $(".box1").click( ( ) => { console.log("123") } )。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 实现$(".box1").click(() => {console.log("123")})
class jquery {
constructor(arg) {
 this.element = document.querySelector(arg);
 // console.log(element);
}
 
click(fn) {
 this.element.addEventListener("click", fn);
}
 
}
 
function $(arg) {
return new jquery(arg);
}
 
//实现$(".box1").click(() => {console.log("123")})
$(".box1").click(() => {
console.log("123")
});

到此为止,我们实现了第一个小目标,大家是不是觉得简单呢,ok,接下来我们继续第二个小目标。

2. 实现$("div").click( )方法

第二个小目标也不难,就是考虑有多个div元素需要绑定click事件,我们用selectSelectorAll来获取元素的话,如何处理,其实也挺简单,就是在click方法中多出一个循环,去获取NodeList中的值。我直接上代码了,大家试一试就知道啦。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Document</title>
 <style> .box1 {
  width: 100px;
  height: 100px;
  background: red;
 }
 .box2 {
  width: 100px;
  height: 100px;
  background: blue;
 } </style>
</head>
 
<body>
 <div class="box1"></div>
 
 <div class="box2"></div>
</body>
 
<script> // 实现$(".box1").click(() => {console.log("123")})
 class jquery {
 constructor(arg) {
  //下面element存的是NodeList对象,它是一个类数组有length属性
  this.element = document.querySelectorAll(arg);
 }
 
 click(fn) {
  for(let i = 0; i < this.element.length; i++) {
  this.element[i].addEventListener("click", fn);
  
 }
 
 }
 
 function $(arg) {
 return new jquery(arg);
 }
 
 //实现$(".box1").click(() => {console.log("123")})
 $("div").click(() => {
 console.log("123")
 }); </script>
 
</html>

好了,完成两个小目标了,相信你已经有成就感了。

3. 考虑$( )中参数的三种情况

接下来第三个小目标 我们来考虑一下$( )中参数不同的情况,我先将三种情况列出来。(可能还有其他情况,这里就不说了)

1.情况一:就是$( )参数为字符串

?
1
$(".box1")

2.情况二:就是$( )参数为函数的情况。

?
1
2
3
4
//参数为函数
 $(function() {
 console.log("123");
 })

3.情况三:就是$( )参数为NodeList对象或selectSelect获得的节点

?
1
2
3
4
5
6
7
// 情况三
 $(document.querySelectorAll("div")).click(()=>{
 console.log("123");
 })
 $(document.querySelector("div")).click(()=>{
 console.log("456");
 })

接下来第三个小目标是手写函数来实现三种情况。 首先我们增加addEles方法,修改上面的click方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
addEles(eles){
  for (let i = 0; i < eles.length; i++) {
  this[i] = eles[i];
  }
  this.length = eles.length;
 }
 
 // 实现$(".box1").click(() => {console.log("123")})
 click(fn) {
  for(let i = 0; i < this.length; i++) {
  this[i].addEventListener("click", fn);
  
 }

接下来实现三种不同参数的处理方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
constructor(arg) {
 
  //情况一
  if(typeof arg === 'string') {
  this.addEles(document.querySelectorAll(arg));
  }else if(typeof arg === 'function') {
  //情况二
  document.addEventListener("DOMContentLoaded", arg);
  }else {
  //情况三
  if(typeof arg.length === 'undefined') {
   this[0] = arg;
   this.length = 1;
  }else {
   this.addEles(arg);
  }
  }
 
 }

4. 实现jq中的on方法

接下来实现第四个小目标 实现jq的on方法

?
1
2
3
4
5
6
7
8
9
10
11
// on方法
 on(eventName, fn) {
  let eventArray = eventName.split(" ");
  //考虑多个节点
  for(let i = 0; i < this.length; i++) {
  //考虑多个事件
  for(let j = 0; j < eventArray.length; j++) {
   this[i].addEventListener(eventArray[j], fn);
  }
  }
 }

再测试下ok不

?
1
2
3
4
// on方法
 $("div").on("mouseover mousedown",function(){
 console.log("on方法");
 })

5. 实现链式操作

接下来实现第五个小目标 实现jq的链式操作

划重点,在on和click中添加return this即可实现链式

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//链式操作
 //划重点,在on和click中添加return this即可实现链式
 // click方法
 click(fn) {
  for(let i = 0; i < this.length; i++) {
  this[i].addEventListener("click", fn);
  }
  return this;
  // console.log(this);
 }
 
 // on方法
 on(eventName, fn) {
  let eventArray = eventName.split(" ");
  //考虑多个节点
  for(let i = 0; i < this.length; i++) {
  //考虑多个事件
  for(let j = 0; j < eventArray.length; j++) {
   this[i].addEventListener(eventArray[j], fn);
  }
  }
  return this;
 }

6. 实现jq中的eq方法

接下来实现第六个小目标 实现jq中的eq方法

?
1
2
3
4
//eq方法
 eq(index) {
  return new jquery(this[index]);
 }

这里通过new一个jquery实现 new的过程大家应该清楚吧,我们温习一下:

  1. 执行函数
  2. 自动创建一个空对象
  3. 将空对象的原型指向构造函数的prototype属性
  4. 将空对象和函数内部this绑定
  5. 如果renturn后跟着对象,返回这个对象。没跟的话就自动返回this对象

7. 实现jq中的end方法

实现第七个小目标 实现jq中的end方法。要实现这个功能,除了新增end( )方法,我们还得在构造函数上实现,constructor新增参数root,新增属性prevObject,并在eq方法这种新增参数this。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
constructor(arg, root) {
  if(typeof root === "undefined") {
  this.prevObject = [document];
  }else {
  this.prevObject = root;
  }
 //eq方法
 eq(index) {
  return new jquery(this[index], this);
 }
 //end方法
 end() {
  return this.prevObject;
 }

8. 实现jq中的css方法

在jq中css可以获取样式,设置一个样式或多个样式

?
1
2
3
4
5
6
7
8
9
10
11
12
// 情况一 :获取样式 (只去获取第一个元素)
 
 let res = $("div").css("background");
 console.log(res);
 
// 情况二 (设置样式)
 
 $("div").css("background","yellow");
 
// // 情况三 (设置多个样式)
 
 $("div").css({background:"black",width:200,opacity:0.3});

接下来实现css方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//css方法
 
 css(...args) {
  if(args.length === 1) {
 
  //情况一:获取样式
  if(typeof args[0] === 'string') {
   return this.getStyle(this[0], args[0]);
  }else {
   //情况三:设置多个样式
   for(let i = 0; i < this.length; i++) {
   for(let j in args[0]) {
    this.setStyle(this[i], j, args[0][j]);
   }
 
   }
  }
  }else {
  //情况三
  for(let i = 0; i < this.length; i++) {
   this.setStyle(this[i], args[0], args[1]);
  }
  }
 } //css方法
 css(...args) {
 if(args.length === 1) {
  //情况一:获取样式
  if(typeof args[0] === 'string') {
  return this.getStyle(this[0], args[0]);
  }else {
  //情况三:设置多个样式
  for(let i = 0; i < this.length; i++) {
   for(let j in args[0]) {
    this.setStyle(this[i], j, args[0][j]);
   }
 
  }
  }
 }else {
  //情况三
  for(let i = 0; i < this.length; i++) {
  this.setStyle(this[i], args[0], args[1]);
  }
 }
 }

增加cssNumber方法来确定不用加px的属性名

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//css方法用
 $.cssNumber = {
 animationIterationCount: true,
 columnCount: true,
 fillOpacity: true,
 flexGrow: true,
 flexShrink: true,
 fontWeight: true,
 gridArea: true,
 gridColumn: true,
 gridColumnEnd: true,
 gridColumnStart: true,
 gridRow: true,
 gridRowEnd: true,
 gridRowStart: true,
 lineHeight: true,
 opacity: true,
 order: true,
 orphans: true,
 widows: true,
 zIndex: true,
 zoom: true
}

最后献上完整代码,如果大哥们觉的不错,给个赞呗

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Document</title>
 <style> .box1 {
  width: 100px;
  height: 100px;
  background: red;
 }
 .box2 {
  width: 100px;
  height: 100px;
  background: blue;
  transform-origin: 0 100% 0;
  transition: 0.3s;
 
 }
 .box2:hover {
  transform: scaleX(2);
  width: 200px;
  height: 100px;
 } </style>
</head>
 
<body>
 <div class="box1"></div>
 
 <div class="box2"></div>
 <button>点击</button>
</body>
 
<script> class jquery {
 
 constructor(arg, root) {
  if(typeof root === "undefined") {
  this.prevObject = [document];
  }else {
  this.prevObject = root;
  }
  //情况一
  if(typeof arg === 'string') {
  this.addEles(document.querySelectorAll(arg));
  }else if(typeof arg === 'function') {
  //情况二
  document.addEventListener("DOMContentLoaded", arg);
  }else {
  //情况三
  if(typeof arg.length === 'undefined') {
   this[0] = arg;
   this.length = 1;
  }else {
   this.addEles(arg);
  }
  }
 
 }
 
 //增加方法
 addEles(eles){
  for (let i = 0; i < eles.length; i++) {
  this[i] = eles[i];
  }
  this.length = eles.length;
 }
 
 //链式操作
 //划重点,在on和click中添加return即可实现链式
 // click方法
 click(fn) {
  for(let i = 0; i < this.length; i++) {
  this[i].addEventListener("click", fn);
  }
  return this;
  // console.log(this);
 }
 
 // on方法
 on(eventName, fn) {
  let eventArray = eventName.split(" ");
  //考虑多个节点
  for(let i = 0; i < this.length; i++) {
  //考虑多个事件
  for(let j = 0; j < eventArray.length; j++) {
   this[i].addEventListener(eventArray[j], fn);
  }
  }
  return this;
 }
 
 //eq方法
 eq(index) {
  return new jquery(this[index], this);
 }
 
 //end方法
 end() {
  return this.prevObject;
 }
 
 //css方法
 css(...args) {
  if(args.length === 1) {
 
  //情况一:获取样式
  if(typeof args[0] === 'string') {
   return this.getStyle(this[0], args[0]);
  }else {
   //情况三:设置多个样式
   for(let i = 0; i < this.length; i++) {
   for(let j in args[0]) {
    this.setStyle(this[i], j, args[0][j]);
   }
 
   }
  }
  }else {
  //情况三
  for(let i = 0; i < this.length; i++) {
   this.setStyle(this[i], args[0], args[1]);
  }
  }
 }
 
 getStyle(ele, styleName) {
  return window.getComputedStyle(ele, null)[styleName];
 }
 setStyle(ele, styleName, styleValue) {
  if(typeof styleValue === "number" && !(styleName in $.cssNumber)) {
  styleValue = styleValue + "px";
  }
  ele.style[styleName] = styleValue;
 }
 
 }
 
 function $(arg) {
 return new jquery(arg);
 }
 
 //css方法用
 $.cssNumber = {
 animationIterationCount: true,
 columnCount: true,
 fillOpacity: true,
 flexGrow: true,
 flexShrink: true,
 fontWeight: true,
 gridArea: true,
 gridColumn: true,
 gridColumnEnd: true,
 gridColumnStart: true,
 gridRow: true,
 gridRowEnd: true,
 gridRowStart: true,
 lineHeight: true,
 opacity: true,
 order: true,
 orphans: true,
 widows: true,
 zIndex: true,
 zoom: true
}
 // //实现情况一:$(".box1")
 // $("div").click(() => {
 // console.log("123")
 // });
 
 // //实现情况二:参数为函数
 // $(function() {
 // console.log('情况2');
 // })
 
 // // 情况三
 // $(document.querySelectorAll("div")).click(()=>{
 // console.log("123");
 // })
 // $(document.querySelector("div")).click(()=>{
 // console.log("456");
 // })
 
 // // on方法
 // $("div").on("mouseover mousedown",function(){
 // console.log("on方法");
 // })
 
 //链式操作
 // $("div").click(() => {
 // console.log("click方法")
 // }).on("mouseover", function() {
 // console.log('链式on方法');
 // })
 
 // $("div").on("mouseover", function() {
 // console.log('链式on方法');
 // }).click(() => {
 // console.log("click方法")
 // })
 
 // //eq方法
 // $("div").eq(0).click(() => {
 // console.log("eq方法")
 // })
 
 //endf方法
 // let res = $("div").eq(0).eq(0).eq(0).end();
 // console.log(res);
 
 //css方法
 
 // 情况一 :获取样式 (只去获取第一个元素)
 // let res = $("div").css("background");
 // console.log(res);
 
 // 情况二 (设置样式)
 // $("div").css("background","yellow");
 
 // // 情况三 (设置多个样式)
 // $("div").css({background:"black",width:200,opacity:0.3}); </script>
</html>

总结

到此这篇关于js实现封装jQuery的简单方法与链式操作的文章就介绍到这了,更多相关js封装jQuery内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://segmentfault.com/a/119000003941249