jQuery的使用与其设计模式

822 阅读4分钟

前言:之前参与项目时,连Javascript都没学明白的我,靠着jQuery也完成了任务,决定走前端这条道路后,我重头开始学JavaScript,DOM…… 学到jQuery时,这次我不再是拿来用用了,而是学习它的设计模式并自己模仿实现JQuery的部分API

👉学习jQuery的设计模式——手写jQuery

jQuery操作元素

选取元素

jQuery基础语法是:$(selector).action()——"选取元素,对其操作",所以第一步就是学习jQuery 如何获取元素。

jQuery 使用 CSS 选择器来选取 HTML 元素,使用 XPath 表达式来选择带有给定属性的元素,也可以是使用特有的过滤表达式来选取元素。

css选择器

jQuery的选择器表达式可以是CSS 选择器来选取 HTML 元素

 $("p") 选取 <p> 元素。

 $("p.intro") 选取所有 class="intro" 的 <p> 元素。

 $("p#demo") 选取所有 id="demo" 的 <p> 元素。

XPath表达式

jQuery的选择器表达式可以是XPath 表达式来选择带有给定属性的元素

 $("[href]") 选取所有带有 href 属性的元素。

 $("[href='#']") 选取所有带有 href 值等于 "#" 的元素。

 $("[href!='#']") 选取所有带有 href 值不等于 "#" 的元素。

 $("[href$='.jpg']") 选取所有 href 值以 ".jpg" 结尾的元素。

过滤表达式

jQuery的选择器表达式可以是jQuery特有的表达式 ,对元素进行过滤,获取到特定的元素

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

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

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

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

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

 $('div:animated') // 选择当前处于动画状态的div元素

查找元素

jQuery提供了在DOM树上移动的方法来查找元素,从被选(当前的)元素开始,在DOM树中向上移动(祖先),向下移动(子孙),水平移动(同胞),这种移动被也称为对 DOM 进行遍历。

 $("span").parent();//返回每个 <span> 元素的的直接父元素

 $("span").parents();//返回所有 <span> 元素的所有祖先

 $("div").children();//返回每个 <div> 元素的所有直接子元素

 $("div").find("span");//返回属于 <div> 后代的所有 <span> 元素

 $("h2").siblings();//返回 <h2> 的所有同胞元素

 $("h2").next();//返回 <h2> 的下一个同胞元素
 //三个最基本的过滤方法是:first(), last() 和 eq()
 $("div p").first();//first() 方法返回被选元素的首个元素

 $("div p").last();//last() 方法返回被选元素的最后一个元素

 $("p").eq(1);//选取第二个 <p> 元素

创建元素

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

但是在上文介绍jQuery的基本语法中,括号中的内容是选择器,为什么现在可以直接传入HTML内容来创建元素?

这就是因为jQuery使用重载的设计模式。

  $('<p>Hello</p>');

 $('<li class="new">new list item</li>');

元素的取值和赋值

jQuery使用同一个API,根据接收参数的不同,来完成取值(getter)或赋值(setter),即"取值器"与"赋值器"合一,这也是jQuery中使用的一种优秀的设计模式。

  • 举例:
$('h1').html(); //html()没有参数,表示取出h1的值

$('h1').html('Hello'); //html()有参数Hello,表示对h1进行赋值
  • 常见的取值和赋值函数
.html() 取出或设置html内容

.text() 取出或设置text内容

.attr() 取出或设置某个属性的值

.width() 取出或设置某个元素的宽度

.height() 取出或设置某个元素的高度

.val() 取出某个表单元素的值

如果结果集包含多个元素,那么赋值的时候,将对其中所有的元素赋值。 取值的时候,则是只取出第一个元素的值(.text()例外,它取出所有元素的text内容)

移动元素

​ jQuery提供两组方法,来操作元素在网页中的位置移动。一组方法是直接移动该元素,另一组方法是移动其他元素,使得目标元素达到我们想要的位置

  • 举例:
//第一种方法是使用.insertAfter()
//把div元素移动p元素后面
$('div').insertAfter($('p'));

//第二种方法是使用.after()
//把p元素加到div元素前面
$('p').after($('div'));

二者区别:返回的元素不一样。第一种方法返回div元素,第二种方法返回p元素。

  • 类似操作方法共4对
 .insertAfter()和.after() //在现存元素的外部,从后面插入元素
 
 .insertBefore()和.before() //在现存元素的外部,从前面插入元素
 
 .appendTo()和.append() //在现存元素的内部,从后面插入元素
 
 .prependTo()和.prepend() //在现存元素的内部,从前面插入元素

删除元素

.remove()——将匹配元素集合从DOM中删除。(注:同时移除元素上的事件及 jQuery 数据)

.detach()——从DOM中去掉所有匹配的元素(注:保留元素上的事件及 jQuery 数据)

.empty()——从DOM中移除集合中匹配元素的所有子节点

链式操作

jquery的核心操作:提供一个函数,参数是选择器,函数内部根据选择器获取这些元素后,返回一个jQuery对象(jquery函数构造出来的对象),后续每一步的jQuery操作也都是返回一个jQuery对象,就实现了链式操作。

$('#test2').find('.child').addClass('green').addClass('blue')

jQuery还提供了.end()方法,使得结果集可以后退一步:

$('#parent').find('.child').addClass('green').end().addClass('old');
//退回到选中的parent上添加old类属性

PS:关于jQuery中其他API,事件、Ajax……参考jQuery中文文档


JQuery中的设计模式

模仿jQuery实现其中的部分API后,也学习到了jQuery中各种优秀的设计模式,现在来简单总结一下。

设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,简单来说就是对优秀的代码模板,起个专业的名字。

链式调用

每一步的jQuery操作,返回的都是一个jQuery对象,参考上文中的链式操作

函数重载

构造函数$()支持多种参数

  • 参数:HTML —— 创建元素
  • 参数:选择器 —— 查找元素

下面的代码模拟了jQuery中重载的实现:

    if (typeof selectorOrArrayOrTemplate === "string") {
        if (selectorOrArrayOrTemplate[0] === "<") {
            // 创建 
            elements = [createElement(selectorOrArrayOrTemplate)];
        } else {
            // 查找 
            elements = document.querySelectorAll(selectorOrArrayOrTemplate);
        }
    } else if (selectorOrArrayOrTemplate instanceof Array) {
        elements = selectorOrArrayOrTemplate;
    }

getter/setter

jQuery使用同一个API,根据接收参数的不同,来完成取值(getter)或赋值(setter)

适配器

jQuery针对不同浏览器使用不同代码

如下代码中:innerText是IE支持的DOM操作,textContent是其他浏览器支持的DOM操作

   text(node, string) {
        if (arguments.length === 2) {
            if ('innerText' in node) { //适配不同的浏览器
                node.innerText = string //ie
            } else {
                node.textContent = string //chrome/firefox
            }
        } else if (arguments.length === 1) {
            if ('innerText' in node) { //适配不同的浏览器
                return node.innerText
            } else {
                return node.textContent
            }
        }
    }

别名

避免浪费内存,jQuery中把所有共有的API放在了jQuery.prototype(原型)中,并为其起了别名jQuery.fn

 window.$ = window.jQuery
 
 jQuery.fn = jQuery.prototype

并且可以用原型继承实现插件系统

 $.fn.modal = function(){ ... }
 
 $('#div1').modal()

用闭包来隐藏细节

对象中各种函数和获得的elements(元素)形成闭包,让用户只能通过函数来操作元素,隐藏了细节

不使用new的构造函数

通过直接调用函数,返回一个对象的方法来得到jQuery对象。

参考

jQuery 都过时了,那我还学它干嘛?

jQuery设计思想

jQuery中文文档