jQuery封装DOM库

165 阅读5分钟

链式风格

也叫jQuery风格,window.jQuery()是我们提供的全局函数

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

准备工作

这是一个图片阵

接受一个选择器,根据这个选择器得到一些元素,然后返回一个对象,这个对象有方法可以操作这个元素

本来返回的应该是elements,但是这里jQuery返回的是一个对象

api是个对象,有个keyaddclass,有个valuefunction

简化 es6提供了新的语法

addClass() { console.log(elements) }

方法实现

让每个class="test"的元素的classList都加一个red

那继续,可不可以返回这个api呢,把return null换成return api

我是不是可以理解为api调用一次addclass返回api,继续调用再返回

神奇的操作

函数如果用一个对象来调用,那么这个函数里面的this就是前面的那个对象。例如:

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

那上面的this是不是就是api,那是不是可以直接返回this

结果不变

最后一下简化,我们声明了一个对象(api),然后返回了这个对象,那可不可以直接返回这个对象呢

  • 总结一下:jQuery核心思想大概就是
    • (1)它提供一个函数,这个函数接受一个选择器,给它这个选择器它就会获取到这个元素,但是它不会返回这个元素,它返回的是一个对象,这个对象有些方法或者函数来操作获取到的元素(用闭包来维持这个elements,只要函数存在,elements就不能消失)
    • (2)通过return this来传递.addClass前面的这个对象,每次传递调用,实现了一个链式操作,叫什么都无所谓,甚至可以直接省略

(一) jQuery('#xxx')

返回值并不是元素,而是一个api对象

(二)查找#xxx里的.red元素

jQuery('#xxx').find('.red')

首先find是一个函数,它接受一个selector,然后要在这个elements里找selector,这里的闭包变量是elements,有多个变量,其实是个数组,数组是不支持querySelectorAll

搞一个新的数组储存新查找的元素,然后遍历elements的每一项

返回的是arrayjQuery操作的对象是elements,就不能进行链式操作了

return this

red加在了test身上,它操作的是elements,而不是array

看着是可以了,但是又有新的问题了

api1是操作test的,api2是操作child的,那最后一个api1加到了child身上是怎么回事!之后改elements的时候会影响所有保留了这个api对象的引用,用的是同一个elements

重新封装一个jQuery函数,jQuery不就是获取一些元素嘛,那就把这些元素(数组)递给jQuery,让它返回一个新的api,这个api和上一个api结构一样但是保存的elements是不一样的

jQuery只接受一个选择器,这里给它的是一个数组,那就让jQuery接受数组,采用重载

  • 这里做了几步操作
    • 1.获取一个新的api,由jQuery另外构造的
    • 2.jQuery不能只接受一个选择器,还要接受一个数组
    • 3.重载,如果是选择器,是elements元素,如果是数组,就把数组赋值给elements
    • 4.作用域的提升,在if{}里的声明作用域只在{}的范围里,且const一旦声明不能更改

简化代码

接下来操作完child再返回去操作test,使用一个end方法实现

就是让这个方法实现,把yellow加到test身上

就多加了两行代码,很简单,很绕,下面的一张图辅助理解一下

这里的end是放到数组身上的,不是放到api身上的,api是要操作数组的

这里插入一句,我们的oldApi也有api,可以对数组进行操作了

运行结果:

(九)遍历并操作

jQuery('#xxx').each(fn) 遍历并对每个元素执行fn,把遍历提前,可以直接用了

each()接受一个函数,然后遍历elements的每一项,然后传两个参数elements[i],ifn,调用这个函数

打印出.test里的.child里的div

打个中断,用each()重写addClassfind

  • find

  • addClass

(三)获取爸爸

jQuery('#xxx').parent()

打印出的是可以操作arrayapi,不是我们要的数组好办,增加一个print方法把elements打印出来就好了

三个test,对应三个body是正确的,改进一下,多个相同的爸爸只打印一个

使用了if语句进行一个判断,就是当(父亲节点不在这个数组里===父亲节点的下标小于0===父亲节点的下标===-1)才push,否则什么都不做

(四)获取儿子

jQuery('#xxx').children()

直接push children会得到一个由数组组成的数组,是一个有结构的数组,而不是一个由所有child组成的数组

又有一个新的语法,展开,像一个省略号

(...node.children) === (node.children[0],node.children[1],node.children[2]...node.children[i])

(五)获取兄弟

jQuery('#xxx').siblings()

(六)获取排行

jQuery('#xxx').index()

(七)获取弟弟

jQuery('#xxx').next()

(八)获取哥哥

jQuery('#xxx').prev()

window.$ = window.jQuery

jQuery太长了,给它一个别名,所有用到jQuery的地方都可以用$代替

下文有$的都是jQuery对象

  • $('<div><span>1</span></div>') 返回值并不是新增的元素,而是api对象
  • $('<div><span>1</span></div>').appendTo(...) appendTo可以把新增的元素放到另一个元素里

(一)获取document.body

$('body')

(二)添加小儿子

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

(三)添加大儿子

$('dody').prepend(div或$div)

(四)添加弟弟

$('#test').after(div或$div)

(五)添加哥哥

$('#test').before(div或$div)

  • $div.remove()
  • $div.empty()

  • $div.text(?)读写文本内容
  • $div.html(?)读写html内容
  • $div.attr('title',?)读写属性
  • $div.css({color:'red'})读写style $div.style更好
  • $div.addClass('blue')/removeClass/hasClass
  • $div.on('click',fn)
  • $div.off('click',fn)

使用原型

最后一步把所有的对象都放到$.prototype,每个对象都只需要存储原型的地址就好了,节省内存

最后的代码

github.com/BarbeHu/dom…