jQuery

72 阅读2分钟

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设计模式实例

  1. jQuery是构造函数吗?

var obj = new Object()构造函数有个特定,前面有个new,所以jQuery是一个不需要加new的构造函数;

jQuery是特殊函数;window.jQuery()是我们提供的全局函数;

  1. jQuery对象代指jQuery函数构造出来的对象,也就是api对象,举例如下:

Object是个函数,Object对象表示Object构造出来的对象

Array是个函数,Array对象/数组对象表示Array构造出来的对象

Function是个函数,Function对象/函数对象表示Function构造出来的对象

  1. jQuery(选择器)用于获取对应的元素,但它不返回这些元素,相反,它返回一个对象,称为jQuery构造出来的对象,这个对象可以操作对应的元素。

路线演进

  1. 创建项目

新建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是全局变量
  1. 运行浏览器

打开vs-code终端,parcel src/index.html,就会开一个服务器,打开即可。

  1. 获取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
  1. jQuery的核心代码是:总体的思路是先接受一个选择器,根据这个选择器得到一些元素,返回一个对象,这个对象有一个方法可以操作这个元素,jQuery获取elements之后,声明了一个api,这个api可以操作elements。也就是说jQuery获取elements,不return elements,而是return可以操作elements的api

  2. 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
}
  1. 以上步骤的实现效果:

image.png

  1. 既然addClass返回的是一个空,那他能不能返回api呢?可以再次返回的,只需要在jQuery.js里面的addClass函数里面,加一行return api就行,如果返回了api,那么main.js里面的api.addClass中 .前面的就是返回的api,也就是可以继续加. 也就是链式操作,如果函数返回的是对象,就可以继续追加返回,所以可以写成如下:
const api = jQuery('.test')    //不返回元素们,返回api对象
api.addClass('red').addClass('blue')      //这就是链式操作
  1. 上述的代码可以简写成:
const api = jQuery('.test')    //不返回元素们,返回api对象
api.addClass('red').addClass('blue')      //这就是链式操作
  1. 回顾前面的this用法:
obj.fn(p1) //函数里的this就是obj
等价于 obj.fn.call(object,p1)

也可以说,this就是api,也就可以把jquery.js里面的return api替换为return this

其实api这个对象是没有名字的,

  1. 再次阐述jQuery的核心思想1:闭包。elements变量和addClass这个函数,jQuery提供一个函数,这个函数接受一个css的选择器,给它这个选择器,就会获取元素,但是不会返回给你这些元素,而是返回对象,这个对象有一些方法,也就是有些函数,这些函数会去操作元素;用闭包维持elements,只要addClass函数不断的访问elements,被访问的东西是不能随便被删掉的。

  2. 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)

最终页面和控制台的效果为:

image.png

  1. 如果有多个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兴衰史