最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 浅析jQuery

    正文概述 掘金(饥人谷一言)   2021-02-06   336

    用jQuery风格重新封装DOM

    为什么学习jQuery

    jQuery 设计模式

    理解jQuery闭包和链式风格

    来自基础之问:jQuery是构造函数吗?

    jQuery 一些函数的实现

    jQuery 的增删改查

    要说的话

       本文主要用来理解jQuery的闭包和链式操作核心思想,以及一些函数的实现。要知道是怎么来的。--资料来源于饥人谷

    推荐阅读文章

    阮一峰jQuery设计思想。本文源代码

    为什么学习jQuery

    jQuery有多牛X

       它是目前前端最长寿的库,2006年发布

       它是世界上使用最广泛的库,到2020年11月也有全球80%的网站在用

    我应该学习设计模式吗?

    • 设计模式不是用来学的

       你看了这些代码,但你并不知道这代码用来解决什么问题等于看了白看

    • 设计模式是用来总结的

       你只管去写代码,把你的代码尽量写好,不断重写。

       总结你的代码,把写得好的地方抽象出来,看看符合哪个设计模式,你就可以告诉别人你用到了这几个设计模式,显得你特别高端

    有人说不用学jQuery

    • 真相

       jQuery这么简单、经典的库为什么不学?

       通过 jQuery可以学会很多封装技巧,为什么不学?

       连jQuery都理解不了, Vue / React肯定学不好

       推荐文章 《jQuery都过时了,那我还学它干嘛?》

    • 学习路线

       理解 jQuery原理

       使用jQuery做一两个项目

       学Vue / React,找工作要紧

    设计模式?

    • jQuery 用到了哪些设计模式

       不用new的构造函数,这个模式没有专门的名字

       $(支持多种参数),这个模式叫做重载

       用闭包隐藏细节,这个模式没有专门的名字

       $div.text()即可读也可写,getter / setter

       $.fn是$.prototype 的别名,这叫别名

       jQuery针对不同浏览器使用不同代码,这叫适配器

    • 设计模式是啥

       设计模式就是对通用代码取个名字

    理解jQuery闭包和链式风格

       链式风格也叫 jQuery风格

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

    • 特殊函数jQuery

       jQuery(选择器)用于获取对应的元素,但它却不返回这些元素,相反,它返回一个对象,称为jQuery构造出来的对象简称jQuery对象

       这个对象可以操作对应的元素

       听不懂?直接写代码!

    上代码理解链式

    在html里

     <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>
    

    jQuery.js

    //核心思想:jQuery接受一个选择器,然后根据选择器得到一些元素,然后返回一个对象,这个对象有个方法去操作这个元素
    window.jQuery = function (selector) {
      //jquery获取elements后,声明个api,这个api可以操作这个elements
      const elements = document.querySelectorAll(selector);
      //elements就是选择器对应的元素
      //---api 可以操作elements---
      const api = {
        //---闭包函数访问外部的变量---。(addClass访问elements,elements是外部的变量)
        addClass(className) {
          for (let i = 0; i < elements.length; i++) {
            elements[i].classList.add(className);
          }
          return api;//返回api对象方便继续调用---链式---
        },
      };
      return api; //jQuery返回一个可以操作elements的api对象。
    };
    
    

    main.js

    const api = jQuery('.test')//不返回元素们,返回api对象
    api.addClass('red')//遍历所有刚才获取的元素,添加 .red
    api.addClass('red').addClass('blue')//链式操作
    //用api调了addClass函数,这个函数返回了前面的api,于是可以继续调用addClass。只需要return 那个对象   
    

    浅析jQuery

    深入链式

       先来看一下this

    obj.fn(p1) //函数里的this就是obj
    obj.fn.call(obj,p1)
    

       main.js里意思是api就是this。那可以直接ruturn this。

    jQuery里代码简化

    window.jQuery = function (selector) {
      //jquery获取elements后,声明个api,这个api可以操作这个elements
      const elements = document.querySelectorAll(selector);
      //elements就是选择器对应的元素
      //---api 可以操作elements---
      return {
        //---闭包:函数访问外部的变量---。(addClass访问elements,elements是外部的变量)
        addClass(className) {
          for (let i = 0; i < elements.length; i++) {
            elements[i].classList.add(className);
          }
          return this;
        },
      };
    };
    
    

    main.js代码简化

    //可以不声明api。简写成
    jQuery(".test")
      .addClass('red')
      .addClass('blue')
      .addClass('green')
    

    示例闭包和链式风格核心思想:

      jQuery提供一个函数,这个函数接受一个css选择器,这个选择器会获取到这些元素,但不会反回elements这些元素,会返回一个对象,对象里可能有一些方法(函数),这些方法会来操作这些元素(用闭包维持elements)。这个函数能猜到你在调用addClass的时候,肯定是通过得到的api的,所以会return this,希望把api.addClass中.前面的东西作为addClass的返回值(传的什么就是this),这样的话就相当于api从前面传递到了后面,传到了后面又可以.addClass....(链式操作))


    jQuery是构造函数吗?

       因为jQuery函数确实构造出了一个对象

    • 不是

       因为不需要写new jQuery()就能构造一个对象,以前讲的构造函数都要结合new才行

    • 结论

       jQuery是一个不需要加new的构造函数

       jQuery不是常规意义上的构造函数

       这是因为jQuery 用了一些技巧

    术语

    • 举例

       Object是个函数,

       Object对象表示 Object构造出的对象。

       Array是个函数,

       Array对象/数组对象表示Array构造出来的对象。

       Function是个函数,

       Function对象/函数对象表示Function构造出来的对象。


    一些实现

    实现find和返回新的api

       实现find

    jQuery.js

    window.jQuery = function (selector) {
      const elements = document.querySelectorAll(selector)
    
      //---api 可以操作elements---
      return {
        //---闭包:函数访问外部的变量---。(addClass访问elements,elements是外部的变量)
        addClass(className) {
          for (let i = 0; i < elements.length; i++) {
            elements[i].classList.add(className);
          }
          return this;
        },
    
        find(selector) {
          //找到当前元素所有匹配选择器的元素,然后把元素放到数组里,在返回这个数组
          let array = []; //思路:我要在test1里找child,可以通过elements去找,但elements是多个元素,可以认为是一个数组,数组是不能querySelectorAll的。只能先声明一个临时的数组,用这个数组去储存新的child元素
    
          for (let i = 0; i < elements.length; i++) {
            const elements2 = Array.from(elements[i].querySelectorAll(selector)); //concat是个伪数组,要变成数组。用之前的空数组连接上新的元素,然后把新的元素的到的新数组在放回array。
            array = array.concat(elements2);
          }
          return array;
        },
    

    main.js

    const x1 = jQuery('.test').find('.child')//获取.test1,查找类为child的元素
    console.log(x1)//x1是个数组,不是一个纯函数,没有链式。
    
    • 遇到的问题:能不能写成链式。

       按照理解链式来看,就算 return this 也是return{}对象,这个对象操作的是elements,就不能操作array。如jQuery('.test').find('.child').addClass('red')现在return this,加到的是test上,find前面的api是test。

      写成链式,返回新的api对象。

       第一步,find函数里return一个新的api,靠jQuery构造出来

          const newApi = jQuery(array);
          //如果直接用同一个api,那每次得到新的元素都会污染之前的api,所以要得到一个新的对象
          return newApi;
          //return jQuery(array)//两行代码简写
    

       第二步,jQuery不能只接受一个选择器,还得接受一个数组:把selector改成selectorOrArray

       第三步,声明elements值为空,然后根据选择器是string还是Array分别赋予不同的值,然后返回一个api去操作它(重载)

    window.jQuery = function (selectorOrArray) {
      //重载
      let elements
      if (typeof selectorOrArray === 'string') {
        elements = document.querySelectorAll(selectorOrArray);
      } else if (selectorOrArray instanceof Array) {
        //对象用instanceof
        elements = selectorOrArray;
      }
    
    

    在main.js里试试

    //去变量
    jQuery('.test')
      .find('.child')
      .addClass('red')
      .addClass('blue')
      .addClass('green')
    

    最后结果,链式成功

    浅析jQuery

       那想返回test再操作呢

       要用到end返回

    实现end

    jQuery.js

        oldApi: selectorOrArray.oldApi,
        
        ···
          
        find(selecor) {
        ...
        array.oldApi = this; //这里this就是旧api
        //把oldApi放到了数组身上并没有放到api身上,插入最上面的代码这样api也有oldApi
        return jQuery(array);
      },
        
        end() {
        return this.oldApi// 这里this就是当前的新的api 
      },
    

    main.js

    //命个名方便理解
    const api1 = jQuery('.test')
    const api2 = api1.find('.child').addClass('red').addClass('blue').addClass('green')
    const oldApi = api2.end().addClass('yellow')
    
    

    end()实现

    浅析jQuery

    实现each

    jQuery.js

        each(fn) {
          //遍历当前所有元素
          for (let i = 0; i < elements.length; i++) {
            fn.call(null, elements[i], i);
          }
          return this//this就是当前api
        },
    

    main.js

    const x = jQuery('.test')
        .find('.child')
    
    x.each((div) => console.log(div))
    
    

    实现each()

    浅析jQuery

    实现爸爸

    jQuery.js

            //实现parent
            //parent不需要参数,直接什么什么.parent
            parent(){
                //获取对应元素的爸爸
                const array = []
                this.each((node)=>{//每一个元素我们要得到一个节点
                    if(array.indexOf(node.parentNode) === -1){//push的时候判断一下,不在里面就是等于-1
                        array.push(node.parentNode)//把这个节点的爸爸放到数组里 
                    }
                })
                return jQuery(array)
                //array没有什么可操作性,所以要封装一个操纵数组的对象,jQuery会返回一个对象,这个对象会操作这些爸爸
            },
            
            print(){//实现print方法把当前elements元素打印出来
                console.log(elements)
            },
    

    main.js

    //爸爸
    const x =jQuery('.test')
    x.parent().print()
    //直接用获取到的api去print一下,它就会操作这些爸爸
    

    浅析jQuery

    实现儿子

    jQuery.js

    
            children(){
                const array = []//准备好一个数组
                this.each((node)=>{
                    array.push(...node.children)//...是把里面的东西拆开,第一个元素当做第一个参数,第二个元素当做第二个参数。
                                                  //等价于(node.children[0], node.children[1],node.children[2]...等等)
                })//遍历刚才的元素,
                return jQuery(array)
            },
    

    main.js

    const x =jQuery('.test')
    
    x.children().print()
    //获取children并打印出来
    

    浅析jQuery


    jQuery的增删改查...

    链式风格-查

    • jQuery('#xxx')返回值并不是元素,而是一个api对象

    • jQuery('#xxx').find ('.red')查找#xxx里的.red元素

    • jQuery('#xxx').parent()获取爸爸

    • jQuery('#xxx').children()获取儿子

    • jQuery('#xxx').siblings()获取兄弟

    • jQuery('#xxx').index()获取排行老几(从O开始)

    • jQuery('#xxx').next()获取弟弟

    • jQuery('#xxx').prev()获取哥哥

    • jQuery('.red').each(fn)遍历并对每个元素执行fn

    命名风格

       嫌弃jQuery太长了?

    • 用$替代jQuery

       代码中所有$开头的变量,都是jQuery 对象

       这是约定,除非特殊说明

    window.$ = window.jQuery = function(selectorOrArray){
    //等号赋值从右忘左执行,也可以在最后写成window.$ = window.jQuery
    ...
    }
    
    • 下面的代码令人误解

       const div = $('div#test')

       我们会误以为div是一个DOM

       实际上div是 jQuery构造的api对象

       怎么避免这种误解呢?

    • 改成这样

       const $div = $('div#test')

       $div.appendChild不存在,因为它不是DOM对象

       $div.find存在,因为它是jQuery对象

    链式风格·删

    1. $div.remove()

    2. $div.empty()

    链式风格·增

    1. $ ('body')获取document.body

    2. $('body' ).append($ ('<div>1</div>'))添加小儿子

    3. $('body').append('<div>1</div>')更方便

    4. $('body').prepend(div或$div)添加大儿子

    5. $('#test').after(div或 $div)添个弟弟

    6. $ ('#test').before(div或 $div)添个哥哥

    $ ('<div><span>1</span></div>')

       返回值并不是新增的元素,而是api对象

    $ ('<div><span>1</span></div>').appendTo(...)

       appendTo可以把新增的元素放到另一个元素里

    • 这是一种什么感觉

       就感觉DOM是不可见的,你不需要知道DOM的任何细节,只需要使用简洁的API即可

       一个好的封装,能让使用者完全不知道内部细节

       这是通过闭包实现的

    我就是想知道细节咋办
    • 举例1

       const $div = $('div#test')

       $div并不是 DOM对象,而是jQuery构造的api对象

       我现在就是想从 $div得到div元素,行不行?

    • 满足你

       $div.get(0)获取第0个元素//div

       $div.get(1)获取第1个元素// undefined

       $div.get(2)获取第2个元素// undefined

       $div.size()得到元素的个数

       $div.length也可以得到元素的个数

       $div.get()获取所有元素组成的数组// [div]

    • 举例2

       const $div= $('.red') //假设有3个div.red

       $div不是DOM对象们,而是jQuery构造的api对象

       我现在就是想从$div得到3个div元素,行不行?

    • 满足你

       $div.get(0)获取第0个元素//div

       $div.get(1)获取第1个元素// div

       $div.get(2)获取第2个元素//div

       $div.size得到元素的个数

       $div.length 也可以得到元素的个数

       $div.get()获取所有元素组成的数组//[div,div,div]

    链式风格·改

    1. $div.text(?)读写文本内容

    2. $div.html(?)读写HTML内容

    3. $div.attr('title',?)读写属性

    4. Sdiv.css({color: 'red"})读写style // $div.style更好

    5. $div.addClass('blue') / removeClass / hasClass

    6. $div.on('click', fn)

    7. $div.off('click', fn)

    • 注意

       $div可能对应了多个div元素

    使用原型

       把共用属性(函数)全都放到$.prototype

       $.fn = $.prototype//名字太长不爽

       然后让api.__proto__指向$.fn





    --continue

    起源地下载网 » 浅析jQuery

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元