38-【JS编程接口】jQuery 中的设计模式


参考文章:
阮一峰的jQuery设计思想
jQuery官方文档

一、jQuery 如何获取元素

jQuery选择网页元素,但是返回元素,而是返回对象,对象里有相应函数对元素进行操作,把api转成this,由于JQuery是window调的,this为window,不可修改,修改的是addClass()函数的api

window.jQuery = function (selector) {
    const elements = document.querySelectorAll(selector)
    const api = {
        addClass(className) {//闭包
            for (let i = 0; i < elements.length; i++) {
                elements[i].classList.add(className)
            }
            return this
        }
    }
    return api
}

简化一下jquery.js,定义了api,又返回了api,省略定义这一步,直接return

window.jQuery = function (selector) {
    const elements = document.querySelectorAll(selector)
    return {
        addClass(className) {
            for (let i = 0; i < elements.length; i++) {
                elements[i].classList.add(className)
            }
            return this
        }
    }
}

具体如何获取元素:

选择表达式可以是CSS选择器

  $(document) //选择整个文档对象

  $('#myId') //选择ID为myId的网页元素

  $('div.myClass') // 选择class为myClass的div元素

  $('input[name=first]') // 选择name属性等于first的input元素

也可以是jQuery特有的表达式

  $('a:first') //选择网页中第一个a元素

  $('tr:odd') //选择表格的奇数行

  $('#myForm :input') // 选择表单中的input元素

  $('div:visible') //选择可见的div元素

  $('div:gt(2)') // 选择所有的div元素,除了前三个

  $('div:animated') // 选择当前处于动画状态的div元素
const api = jQuery('.test') //返回的不是元素,而是对象
//向遍历的所有对象里添加.red,.blue,.yellow
api.addClass('red')
    .addClass('blue')
    .addClass('yellow')
//this就是api
<div class="test red blue">你好3</div>

简化下main.js

jQuery('.test')
.addClass('red')
    .addClass('blue')
    .addClass('yellow')
二、jQuery是构造函数吗?

他是不需要加new的构造函数,但又不是常规意义上的构造函数

口头约定术语

jQuery对象:是jQuery函数构造出来的对象

Object对象:是Object构造函数构造出来的对象

Array对象/数组对象:是Array构造函数构造出来的对象

Function对象:是Function构造函数构造出来的对象

三、jQuery元素实现find函数

查找#xxx里的.red元素 :jQuery.find(’#xxx’).find(’.red’)

现在返回的是数组,没法调用同一个api

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
}

$div.find返回新的api对象

  • 利用jQuery创一个新的newApi
  • 把JQuery函数设置参数为字符串或者数组,为字符串时装换成数组,为数组直接返回数组
  • 返回newApi
window.jQuery = function (selectorOrArray) {
    let elements
    if (typeof selectorOrArray === 'string') {
        elements = document.querySelectorAll(selectorOrArray)
    } else if (selectorOrArray instanceof Array) {
        elements = selectorOrArray
    }
    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
        }
    }

}

const api1 = jQuery('.test') //返回的不是元素,而是对象
api1.addClass('blue')
const api2 = jQuery('.test').find('.child').addClass('.red')
api1.addClass('green')

结果

<div class="test blue green">你好1
    <div class="child .red">child1</div>
    <div class="child .red">child2</div>
    <div class="child .red">child3</div>
</div>

简化一下

return jQuery(array)
<div class="child .red .blue yellow">child1</div>
jQuery('.test')
    .find('.child')
    .addClass('.red')
    .addClass('.blue')
    .addClass('yellow')
五、jQuery实现end函数
  • oldApi: selectorOrArray.oldApi,
  • array.oldApi = this //this就是旧Api
  • end() {
    return this.oldApi // this就是新Api
    }
window.jQuery = function (selectorOrArray) {
    let elements
    if (typeof selectorOrArray === 'string') {
        elements = document.querySelectorAll(selectorOrArray)
    } else if (selectorOrArray instanceof Array) {
        elements = selectorOrArray
    }
    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)
                //数组=元素+空数组
            }
            array.oldApi = this //this就是旧Api
            return jQuery(array)
        },
        oldApi: selectorOrArray.oldApi,
        end() {
            return this.oldApi //    this就是新Api
        }
    }

    jQuery('.test')
    .find('.child')
    .addClass('.red')
    .addClass('.blue')
    .addClass('yellow')
    .end()
    .addClass('green2') //作用于test上
六、jQuery实现each()函数

获得所有的.child类的div

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

each(fn) {
  for (let i = 0; i < elements.length; i++) {
    fn.call(null, elements[i], i);
  }
  return this;
}
七、jQuery实现parent函数
parent() {
    const arr = []
    this.each((node) => {
        arr.push(node.parentNode)
    })
    return jQuery(arr)
},

//let x = jQuery('.test').parent()
//x.each((div) => console.log(div)) 
jQuery('.test').parent().print() 打出数组

得到三个body,判断一下arr.parentNode的下标是否为-1

parent() {
    const arr = []
    this.each((node) => {
        if (arr.indexOf(node.parentNode) === -1) {
            arr.push(node.parentNode)
        }
    })
    return jQuery(arr)
},
print() {
    console.log(elements)
},
八、jQuery实现children()函数

…node.children把数组里的都显示出来

jQuery('.test').children().print()

children() {
    const array = []
    this.each((node) => {
        array.push(...node.children)
    })
    return jQuery(array)
},

实现一下:http://js.jirengu.com/wibifopome/17/edit?html,css,js,output

八、jQuery命名

简化JQuery:$符代替

window.$ = window.jQuery = function (){}
//两个等于号是从右向左的

命名风格:$div与div

DOM对象—DOM的API 如querySelector、appendChild

JQuery对象----JQuery的API 如find、each

所以采用div前加前缀,$div

const eldiv1 = document.querySelector('.test')
const $div = jQuery('.test')//操作这个对象的api,不是div 
九、jQuery 如何创建、删除、清空元素

创建div $('<div>1</div>')

创建新元素的方法非常简单,只要把新元素直接传入jQuery的构造函数就行了

$div.remove()

$div.empty()

十、jQuery 如何修改元素的属性

d i v 多 为 数 组 , 需 要 遍 历 一 下 , div多为数组,需要遍历一下, divdiv常为多个数

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

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

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

读写Style $div.css({color:'red'}) css改变是样式

加class类 $div.add('blue')

点击事件 $div.on('click',fn)

清除事件$div.off('click',fn)

JQuery原型

$.fn = ==jQuery.prototype===api.__proto__

第一步:把共有属性放在Jquery,prototype里

jQuery.prototype = {
    constructor: jQuery,
    jquery: true,
    get(index) {

第二步:以共有属性创建api

const api = this.Object.create(jQuery.prototype)

第三步:给创建的对象加自身属性

    Object.assign(api, {
        elements: elements,
        oldApi: selectorOrArray.oldApi,
    })

问题点:

elements的作用域是JQuery()函数里:把函数外的以this.elements修改

jQuery.prototype 里必须有constructor: jQuery,jquery: true,

JQuery涉及的设计模式

1.不用new的构造函数模式

2.重载:$(支持多种参数)

3.闭包隐藏细节(elements变量在函数里操纵)

4.getter/setter模式:$div.text()

5.别名:$.fn=jQuery.prototype

6.适配器:对不同浏览器用不同代码(if else)

7.封装:把变量放在函数中,暴露出api,api可以操作这些变量

更多设计模式在写代码中发现,就是给通用代码取个名字而已

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值