jQuery
jQuery解决了浏览器兼容问题。开发者写的代码在标准浏览器中正常运行,而在IE浏览器中就挂掉了,这就造成面对同样的需求写两遍代码,分别用在标准浏览器和IE上,因为毕竟当时IE的市场份额不少。
jQuery核心代码
window.jQuery = function(selector){
const elements = document.querySelectorAll(selector)
//element就是这个选择器对应的元素
const api = {
addClass(className){
for(let i=0; i<elements.length; i++){
elements[i].classList.add(className)
}
}
return api
}
jQuery提供一个函数,这个函数接受一个css的选择器,给它这个选择器,就会获取元素,但是不会返回给你这些元素,而是返回对象,这个对象有一些方法,也就是有些函数,这些函数会去操作元素。
也就是说jQuery获取elements,不返回 elements,而返回可以操作elements的api
jQuery核心思想
闭包 和 链式操作
jQuery 对比 MVVM
jQuery后期,MVVM框架兴起,也就是MVC项目分层的变种.
jQuery完全照搬了原生DOM的开发模式。在页面的DOM树,对于要改变数据就拿到一个节点进行操作,完成以后再插回去;对于要添加元素就创建一个节点进行操作,然后插到DOM树中;
MVVM是一种采用虚拟DOM的开发模式。用JS对象实现的一个假的模拟的DOM树,用Diff算法来判别节点操作前后的具体变化,优化了传统jQuery频繁数据对比和操作DOM,大幅提高了性能。在继承方面,css3替代了jQuery动画效果,axios替代了jQuery的ajax方法。
jQuery设计模式实例
- jQuery是构造函数吗?
var obj = new Object()构造函数有个特定,前面有个new,所以jQuery是一个不需要加new的构造函数;
jQuery是特殊函数;window.jQuery()是我们提供的全局函数;
- jQuery对象代指jQuery函数构造出来的对象,也就是api对象,举例如下:
Object是个函数,Object对象表示Object构造出来的对象
Array是个函数,Array对象/数组对象表示Array构造出来的对象
Function是个函数,Function对象/函数对象表示Function构造出来的对象
jQuery(选择器)用于获取对应的元素,但它不返回这些元素,相反,它返回一个对象,称为jQuery构造出来的对象,这个对象可以操作对应的元素。
路线演进
- 创建项目
新建dom-2文件夹,vscode打开文件夹,新建src文件夹,并创建三个文件
index.html
jquery.js
main.js
创建时的代码为:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>手写jQuery</title>
</head>
<body>
hello
<script src="jquery.js"></script> //实现jquery.js的内容,封装的过程
<script src="main.js"></script> //实现main.js的内容,直接调用
</body>
</html>
window.jQuery = function(){
console.log('我是 jQuery')
}
window.jQuery() //完整写法,可删掉window. 用下面的简写代替
jQuery() //省略写法,因为jQuery是全局变量
- 运行浏览器
打开vs-code终端,parcel src/index.html,就会开一个服务器,打开即可。
- 获取div
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>手写jQuery</title>
</head>
<body>
<div class="test"> //main.js不确定有多少个div,就用类来定义
hello
</div>
<script src="jquery.js"></script> //实现jquery.js的内容,封装的过程
<script src="main.js"></script> //实现main.js的内容,直接调用
</body>
</html>
window.jQuery = function(selector){
const elements = document.querySelectorAll(selector)
//element就是这个选择器对应的元素
return elements //按常规应该是return elements,但是不是这样的
const api = {
addClass(){
console.log(elements)
}
// 原写法是
const api ={
"addClass":function(){console.log(elements)}
}
// api是个对象,它的key是addClass,value是函数
// 这就是闭包,函数访问外部的变量。addClass访问elements
return api
}
const api = jQuery('.test') //不返回元素们,返回api对象
api.addClass('red') //遍历所有刚才获取的元素,添加 .red
-
jQuery的核心代码是:总体的思路是先接受一个选择器,根据这个选择器得到一些元素,返回一个对象,这个对象有一个方法可以操作这个元素,jQuery获取elements之后,声明了一个api,这个api可以操作elements。也就是说jQuery获取elements,不return elements,而是return可以操作elements的api
-
main.js里面的第一行代码,
const api = jQuery('.test')先获取到.test定义的所有元素,因为不知道获取到的api操作的元素是几个,就遍历所有刚才获取的元素,并全部添加 .red,api.addClass('red'),细化jQuery.js内容:
window.jQuery = function(selector){
const elements = document.querySelectorAll(selector)
//element就是这个选择器对应的元素
return elements //按常规应该是return elements,但是不是这样的
const api = {
addClass(className){
for(let i=0; i<elements.length; i++){
elements[i].classList.add(className)
}
}
return api
}
- 以上步骤的实现效果:
- 既然addClass返回的是一个空,那他能不能返回api呢?可以再次返回的,只需要在jQuery.js里面的addClass函数里面,加一行
return api就行,如果返回了api,那么main.js里面的api.addClass中 .前面的就是返回的api,也就是可以继续加. 也就是链式操作,如果函数返回的是对象,就可以继续追加返回,所以可以写成如下:
const api = jQuery('.test') //不返回元素们,返回api对象
api.addClass('red').addClass('blue') //这就是链式操作
- 上述的代码可以简写成:
const api = jQuery('.test') //不返回元素们,返回api对象
api.addClass('red').addClass('blue') //这就是链式操作
- 回顾前面的this用法:
obj.fn(p1) //函数里的this就是obj
等价于 obj.fn.call(object,p1)
也可以说,this就是api,也就可以把jquery.js里面的return api替换为return this
其实api这个对象是没有名字的,
-
再次阐述jQuery的核心思想1:闭包。elements变量和addClass这个函数,jQuery提供一个函数,这个函数接受一个css的选择器,给它这个选择器,就会获取元素,但是不会返回给你这些元素,而是返回对象,这个对象有一些方法,也就是有些函数,这些函数会去操作元素;用闭包维持elements,只要addClass函数不断的访问elements,被访问的东西是不能随便被删掉的。
-
jQuery的核心思想2:链式操作,addClass,return的是this,这个this就是addClass前面的东西,可以是api,或者任意别的x,既然声明变量x,然后马上就用x,就可以不用声明了,
jQuery('.test')
.addClass('red')
.addClass('blue')
.addClass('green')
链式风格的增删改查
先构造出来一组div, 用find查找元素的时候,因为除了this是api之外,还有一个闭包变量是elements,可以用它去找,但是elements是多个元素,可以看成是数组,而数组是不能用elements.querySelectorAll这个的,只能声明一个临时的数组,来储存新查找的元素,再遍历elements,用每一个elements去找对应的选择器,就得到这些元素,怎么放进数组里面呢,用之前的空数组连接上新的元素,然后把这个新的元素,再放回array,可以理解成array = array + elements2:
<div class="test1">
你好1
<div class="child">child1</div>
<div class="child">child2</div>
<div class="child">child3</div>
</div>
find(selector){
let array = []
for(let i=0; i<elements.length;i++){
array = array.concat(Array.from(elements[i].querySelectorAll(selector)))
}
return array
}
const x1 = jQuery('.test1').find('.child')
console.log(x1)
最终页面和控制台的效果为:
- 如果有多个test的情况:
<body>
<div class="test">
你好1
<div class="child">child1</div>
<div class="child">child2</div>
<div class="child">child3</div>
</div>
<div class="test">
你好2
<div class="child">child1</div>
<div class="child">child2</div>
</div>
<div class="test">
你好3
</div>
<script src="jquery.js"></script>
<script src="main.js"></script>
</body>
参考
project from jirengu.com
b站up主晓舟报告-jQuery兴衰史