- 用jQuery风格重新封装
- 实现find函数
- 实现end函数
- 什么?你嫌jQuery太长?
-曾老湿, 江湖人称曾老大。
-多年互联网运维工作经验,曾负责过大规模集群架构自动化运维管理工作。 -擅长Web集群架构与自动化运维,曾负责国内某大型金融公司运维工作。 -devops项目经理兼DBA。 -开发过一套自动化运维平台(功能如下): 1)整合了各个公有云API,自主创建云主机。 2)ELK自动化收集日志功能。 3)Saltstack自动化运维统一配置管理工具。 4)Git、Jenkins自动化代码上线及自动化测试平台。 5)堡垒机,连接Linux、Windows平台及日志审计。 6)SQL执行及审批流程。 7)慢查询日志分析web界面。
用jQuery风格重新封装
创建项目 |
---|
创建一个dom-2项目
使用 VScode 打开

index.html
代码语言:javascript复制<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>曾老湿 手写 jQuery</title>
</head>
<body>
你好
<script src="jquery.js"></script>
<script src="main.js"></script>
</body>
</html>
jquery.js
代码语言:javascript复制window.jQuery = function(){
console.log('我是jQuery')
}
main.js
代码语言:javascript复制jQuery()
使用parcel运行以上代码,测试
代码语言:javascript复制MacBook-pro:dom-2 driverzeng$ parcel src/index.html

链式风格 |
---|
也叫jQuery风格
window.jQuery()使我们提供的全局函数
特殊函数jQuery jQuery(选择器)用于获取对应的元素 但是它却不返回这些元素 相反,它返回一个对象,称为jQuery构造出来的对象 这个对象可以操作对应的元素
index.html
代码语言:javascript复制<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>曾老湿 手写 jQuery</title>
</head>
<body>
<div class="test">
你好1
</div>
<div class="test">
你好2
</div>
<div class="test">
你好3
</div>
<script src="jquery.js"></script>
<script src="main.js"></script>
</body>
</html>
jquery.js
代码语言:javascript复制window.jQuery = function(selector){
const elements = document.querySelectorAll(selector)
// api 可以操作elements
const api = {
// 闭包:函数访问外部变量
addClass(className){
for(let i=0;i<elements.length;i ){
elements[i].classList.add(className)
}
return this
}
}
return api
}
main.js
代码语言:javascript复制const api = jQuery('.test') // 不返回元素们,返回api对象
api.addClass('red') // this 就是 api
.addClass('green') // this 就是 api
.addClass('blue') // 链式操作

代码优化:那我们是不是可以把const api这个变量去掉?直接return下面的函数,代码如下:
jquery.js
代码语言:javascript复制window.jQuery = function(selector){
const elements = document.querySelectorAll(selector)
// api 可以操作elements
return {
// 闭包:函数访问外部变量
addClass(className){
for(let i=0;i<elements.length;i ){
elements[i].classList.add(className)
}
return this
}
}
}
当我们调用的时候 ,是不是也可以不加api?代码如下:
main.js
代码语言:javascript复制jQuery('.test') // 不返回元素们,返回api对象
.addClass('red') // this 就是 api
.addClass('green') // this 就是 api
.addClass('blue') // 链式操作
实现find函数
jQuery是构造函数么?
是,因为jQuery函数确实构造了一个对象
不是,因为不需要写new jQuery()
就能构造一个对象
结论: 1.jQuery是一个不需要加new的构造函数 2.jQuery不是常规意义上的构造函数 3.这是因为jQuery用了一些技巧
那么我们可以使用链式风格
来实现增删改查
查 |
---|
jQuery('#xxx') 返回值并不是元素,而是一个api对象: 该功能已实现
jQuery('#xxx').find('.red') 查找#xxx里的.red元素
index.html
代码语言:javascript复制<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>曾老湿 手写 jQuery</title>
</head>
<body>
<div class="test1">
你好1
<div class="child">child1</div>
<div class="child">child2</div>
<div class="child">child3</div>
</div>
<div class="test2">
你好2
</div>
<div class="test3">
你好3
</div>
<script src="jquery.js"></script>
<script src="main.js"></script>
</body>
</html>
main.js
代码语言:javascript复制const x1 = jQuery('.test1').find('.child')
console.log(x1)
jquery.js
代码语言:javascript复制window.jQuery = function(selector){
const elements = document.querySelectorAll(selector)
// api 可以操作elements
return {
// 闭包:函数访问外部变量
addClass(className){
for(let i=0;i<elements.length;i ){
elements[i].classList.add(className)
}
return this
},
find(selector){
let array = []
for(let i=0;i<elements.length;i ){
const elements2 = Array.from(elements[i].querySelectorAll(selector))
array = array.concat(elements2)
}
return array
}
}
}

但是问题出来了,如果说,我找到child,让后想往child后面加.red,该如何添加?
main.js
代码语言:javascript复制const x1 = jQuery('.test1').find('.child')
console.log(x1)
x1.addClass('.red')
然后会发现,array是一个数组啊,数组是不能添加的,浏览器会报错

那么我们可不可以,再返回一个this?
jquery.js
代码语言:javascript复制window.jQuery = function(selector){
const elements = document.querySelectorAll(selector)
// api 可以操作elements
return {
// 闭包:函数访问外部变量
addClass(className){
for(let i=0;i<elements.length;i ){
elements[i].classList.add(className)
}
return this
},
find(selector){
let array = []
for(let i=0;i<elements.length;i ){
const elements2 = Array.from(elements[i].querySelectorAll(selector))
array = array.concat(elements2)
}
return this
}
}
}
 它并没有把.red 加到child上,我们把main.js的代码简化一下
main.js
代码语言:javascript复制jQuery('.test1').find('.child').addClass('.red')
实际上它加到了find前面的api于是乎,就加到了test1上了,那么我们只能重新封装,得到新的api
jquery.js
代码语言:javascript复制window.jQuery = function(selectorOrArray){
let elements
if(typeof selectorOrArray === 'string'){
elements = document.querySelectorAll(selectorOrArray)
}else if(selectorOrArray instanceof Array){
elements = selectorOrArray
}
// api 可以操作elements
return {
// 闭包:函数访问外部变量
addClass(className){
for(let i=0;i<elements.length;i ){
elements[i].classList.add(className)
}
return this
},
find(selector){
let array = []
for(let i=0;i<elements.length;i ){
const elements2 = Array.from(elements[i].querySelectorAll(selector))
array = array.concat(elements2)
}
const newApi = jQuery(array)
return newApi
}
}
}

来点别的需求
先给test1定义为api1 然后加上blue,然后给api2赋值是找到test1的child给他red,再杀一个回马枪,给api1添加green
main.js
代码语言:javascript复制const api1 = jQuery('.test1')
api1.addClass('blue')
const api2 = api1.find('.child').addClass('red')
api1.addClass('green')

jQuery('#xxx').parent() 获取爸爸
jquery.js
代码语言:javascript复制window.jQuery = function(selectorOrArray){
let elements
if(typeof selectorOrArray === 'string'){
elements = document.querySelectorAll(selectorOrArray)
}else if(selectorOrArray instanceof Array){
elements = selectorOrArray
}
// api 可以操作elements
return {
oldApi: selectorOrArray.oldApi,
// 闭包:函数访问外部变量
addClass(className){
for(let i=0;i<elements.length;i ){
elements[i].classList.add(className)
}
return this
},
find(selector){
let array = []
for(let i=0;i<elements.length;i ){
const elements2 = Array.from(elements[i].querySelectorAll(selector))
array = array.concat(elements2)
}
array.oldApi = this // this就是 旧api
const newApi = jQuery(array)
return newApi
},
each(fn){
for(let i=0;i<elements.length;i ){
fn.call(null,elements[i],i)
}
return this
},
print(){
console.log(elements)
},
parent(){
const array = []
this.each((node)=>{
if(array.indexOf(node.parentNode) === -1){
array.push(node.parentNode)
}
})
return jQuery(array)
},
end(){
return this.oldApi
}
}
}
main.js
代码语言:javascript复制const x = jQuery('.test1')
x.parent().print()

jQuery('#xxx').children() 获取儿子
jquery.js
代码语言:javascript复制window.jQuery = function(selectorOrArray){
let elements
if(typeof selectorOrArray === 'string'){
elements = document.querySelectorAll(selectorOrArray)
}else if(selectorOrArray instanceof Array){
elements = selectorOrArray
}
// api 可以操作elements
return {
oldApi: selectorOrArray.oldApi,
// 闭包:函数访问外部变量
addClass(className){
for(let i=0;i<elements.length;i ){
elements[i].classList.add(className)
}
return this
},
find(selector){
let array = []
for(let i=0;i<elements.length;i ){
const elements2 = Array.from(elements[i].querySelectorAll(selector))
array = array.concat(elements2)
}
array.oldApi = this // this就是 旧api
const newApi = jQuery(array)
return newApi
},
each(fn){
for(let i=0;i<elements.length;i ){
fn.call(null,elements[i],i)
}
return this
},
print(){
console.log(elements)
},
parent(){
const array = []
this.each((node)=>{
if(array.indexOf(node.parentNode) === -1){
array.push(node.parentNode)
}
})
return jQuery(array)
},
children(){
const array = []
this.each((node)=>{
if(array.indexOf(node.parentNode) === -1){
array.push(...node.children)
// ... 代表 array.push(node.children[0],node.children[1],node.children[2]...)因为不知道有几个元素 所以用...把数组拆开
}
})
return jQuery(array)
},
end(){
return this.oldApi
}
}
}
main.js
代码语言:javascript复制const x = jQuery('.test1')
x.children().print()

jQuery('#xxx').siblings() 获取兄弟 jQuery('#xxx').index() 获取排行老几(从0开始) jQuery('#xxx').next() 获取弟弟 jQuery('#xxx').prev 获取哥哥 jQuery('#xxx').each(fn) 遍历并对每个元素执行fn
jquery.js
代码语言:javascript复制window.jQuery = function(selectorOrArray){
let elements
if(typeof selectorOrArray === 'string'){
elements = document.querySelectorAll(selectorOrArray)
}else if(selectorOrArray instanceof Array){
elements = selectorOrArray
}
// api 可以操作elements
return {
oldApi: selectorOrArray.oldApi,
// 闭包:函数访问外部变量
addClass(className){
for(let i=0;i<elements.length;i ){
elements[i].classList.add(className)
}
return this
},
find(selector){
let array = []
for(let i=0;i<elements.length;i ){
const elements2 = Array.from(elements[i].querySelectorAll(selector))
array = array.concat(elements2)
}
array.oldApi = this // this就是 旧api
const newApi = jQuery(array)
return newApi
},
each(fn){
for(let i=0;i<elements.length;i ){
fn.call(null,elements[i],i)
}
return this
},
end(){
return this.oldApi
}
}
}
实现end函数
用end表示上一个api结束 |
---|
jquery.js
代码语言:javascript复制window.jQuery = function(selectorOrArray){
let elements
if(typeof selectorOrArray === 'string'){
elements = document.querySelectorAll(selectorOrArray)
}else if(selectorOrArray instanceof Array){
elements = selectorOrArray
}
// api 可以操作elements
return {
oldApi: selectorOrArray.oldApi,
// 闭包:函数访问外部变量
addClass(className){
for(let i=0;i<elements.length;i ){
elements[i].classList.add(className)
}
return this
},
find(selector){
let array = []
for(let i=0;i<elements.length;i ){
const elements2 = Array.from(elements[i].querySelectorAll(selector))
array = array.concat(elements2)
}
array.oldApi = this // this就是 旧api
const newApi = jQuery(array)
return newApi
},
end(){
return this.oldApi
}
}
}
main.js
代码语言:javascript复制jQuery('.test1')
.addClass('blue')
.find('.child')
.addClass('red')
.addClass('green')
.end()
.addClass('yellow')

什么?你嫌jQuery太长?
那么我们来解决这么一个小问题,有的时候我们写jQuery,一会小写一会大写,敲起来很费劲,那么我们在调用的时候,可以把它简化,只需要在代码中加入一句话。
代码语言:javascript复制window.$ = window.jQuery
那么后台调用如下:
代码语言:javascript复制// 之前调用方式
jQuery('.test1')
.children().print()
// 简化调用方式
$('.test1')
.children().print()


还可以继续简化,我们把代码折叠后,会发现,window.jQuery = fn
,window.$ = window.jQuery
所以,我们是不是可以用小学学习的数学知识等量代换
window.$ = window.jQuery = fn
最终代码如下:
代码语言:javascript复制window.$ = window.jQuery = function(selectorOrArray){
let elements
if(typeof selectorOrArray === 'string'){
elements = document.querySelectorAll(selectorOrArray)
}else if(selectorOrArray instanceof Array){
elements = selectorOrArray
}
// api 可以操作elements
return {
oldApi: selectorOrArray.oldApi,
// 闭包:函数访问外部变量
addClass(className){
for(let i=0;i<elements.length;i ){
elements[i].classList.add(className)
}
return this
},
find(selector){
let array = []
for(let i=0;i<elements.length;i ){
const elements2 = Array.from(elements[i].querySelectorAll(selector))
array = array.concat(elements2)
}
array.oldApi = this // this就是 旧api
const newApi = jQuery(array)
return newApi
},
each(fn){
for(let i=0;i<elements.length;i ){
fn.call(null,elements[i],i)
}
return this
},
print(){
console.log(elements)
},
parent(){
const array = []
this.each((node)=>{
if(array.indexOf(node.parentNode) === -1){
array.push(node.parentNode)
}
})
return jQuery(array)
},
children(){
const array = []
this.each((node)=>{
if(array.indexOf(node.parentNode) === -1){
array.push(...node.children)
// ... 代表 array.push(node.children[0],node.children[1],node.children[2]...)因为不知道有几个元素 所以用...把数组拆开
}
})
return jQuery(array)
},
end(){
return this.oldApi
}
}
}