黄子涵

第12章 库

绩效

章节 代码量(行)
12.1 0
12.2 0
12.3 122

12.1 使用库的原因

在客户端 JavaScript 中,最为费时费力的事就是跨浏览器支持,更进一步说,是对 Internet Explorer 的支持。Internet Explorer 6、7、8 之间都有着细微的功能差异,而且从浏览器市场份额的角度来看,这真是一个不可忽视的麻烦问题。当然了,很多大型网站已经不再支持 Internet Explorer 6,所以忽略它可能也不会有什么问题。例如,Yahoo! JAPAN 已经不支持 Internet Explorer 6,Google 则将 Google Apps 所支持的浏览器限定为最新版的 Google Chrome、Firefox、Safari、Internet Explorer 及其上一个版本。

然而,即使不考虑 Internet Explorer 6,仍然无法逃脱 Internet Explorer 的束缚。要让每一个开发者各自解决这一问题是不可行的,应该通过已经被很多网站所使用的库来尽可能地减少花费在跨浏览器支持上的时间与精力。话虽如此,库也不是完美无缺的。对于库无法涵盖的部分,仍需要自己书写跨浏览器支持的代码。在充分使用了库的基础上,理解浏览器的功能,在不得已的情况下自己写出相应的处理,这一点很重要。

如果要开发真正的 Web 应用,就必定需要使用库。不过,如果仅仅知道库的使用方法,发生问题时还是无法解决。因此,至少还应该掌握之前所说的那些知识,并在此基础上,理解使用库所能带来的优点并对其恰当地加以利用。

12.2 jQuery的特征

jQuery 是现在世界上使用最多的 JavaScript 库,其作者为 John Resig,可以通过下面的 URL访问 jQuery 的官方站点。jQuery 是通过 MIT 许可进行发布的。
http://jquery.com/

jQuery 具有以下特征。

  • 压缩后仅有 31KB,非常轻巧
  • 通过链式语法实现
  • 通过 CSS3 选择器及自定义选择器获取元素
  • 支持插件,可扩展性高

jQuery 并不包含 UI 组件。jQuery 另有一个独立的 UI 组件,名为 jQuery UI。jQuery UI 的官方站点如下所示。
http://jqueryui.com/

12.3 jQuery的基本概念

12.3.1 使用实例

在使用 jQuery 时,由于其采用了自定义的选择器以及链式语法,因此看起来像是在书写不同于JavaScript 的另一种语言。例如,点击 foo 类中的第一个 div 元素时,创建一个链接并将其添加
的操作,可以像代码清单 12.1 这样来书写。

代码清单 12.1 jQuery 的使用实例
<!DOCTYPE html>
<html lang="zh">

<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>
    <script src="jquery-3.5.1.js"></script>
</head>

<body>
   <button class="hzh">点击该按钮时,添加一个链接</button>
   <button class="hzh">该按钮不会有反应</button>
   <script>
       // 对点击class="hzh"的第一个button元素时的处理进行设定
       $('button.hzh:first').click(function() {
           $('<div><a></a></div>')                         // 创建div元素。div元素中a元素这一子元素
                                                           // 这时选择的是div元素
           .find('a')                                      // 对a元素进行选择。所选择的目标从div元素转为了a元素
                .text('www.huangzihan.top')                // 将a元素的文本设定为jQuery.com
                .attr('href', 'http://www.huangzihan.top') // 将a元素的href属性设定为http://jquery.com
           .end()                                          // 结束对a元素的选择
                                                           // 在a元素被选择之前所选中的div元素回到了被选择的状态
           .appendTo('body');                              // 将div元素添加至body
       });
   </script>
</body>

</html>

image

尽管上面例子中的功能并没有什么特别意义,不过也能从中看出借助 jQuery 就能够实现简洁的书写。在某个元素触发了事件之后对另一个元素进行操作是在 JavaScript 中常见的处理,而对此 jQuery 只需要书写这么一点的代码就能实现。完全不需要使用 getElementById() 或 firstChild 之类的 DOM API。可以说 jQuery 是尽可能地隐藏了 DOM API 并对其进行了重新定义。

作为比较,在代码清单 12.2 中没有使用jQuery,而是通过标准的 JavaScript 与 DOM API 来实现上一个例子中的功能

代码清单 12.2 不使用 jQuery 的例子
<!DOCTYPE html>
<html lang="zh">

<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>
   <button class="hzh">点击该按钮时,添加一个链接</button>
   <button class="hzh">该按钮不会有反应</button>
   <script>
       // 对点击class="hzh"的第一个button元素时的处理进行设定
       var onClick = function() {
           var div = document.createElement('div');
           var a = document.createElement('a');
           a.appendChild(document.createTextNode('www.huangzihan.top'));
           a.href = 'http://www.huangzihan.top'
           div.appendChild(a);
           document.body.appendChild(div);
       };

       // 通过 getElementBytagName() 来获取所有的 button 元素
       var buttons = document.getElementsByTagName('button');
       // 在所取得的 button 元素中找到第一个类名包含了 hzh 的元素
       // 对点击事件设定事件侦听器
       for (var i = 0, len = buttons.length; i < len; i++) {
           if (buttons[i].className.match(/(^|\s)hzh(\s|$)/)) {
               buttons[i].addEventListener('click', onClick, false);
               break;
           }
       }
   </script>
</body>

</html>

image

或许仅仅是这种程度的功能还不至于使书写变得过于复杂,但代码量几乎是倍增。在使用 jQuery 时无需用到的变量、DOM API、if 语句以及 for 语句等控制语句的书写使得代码量增加。而变量与控制语句的使用也会增加出现错误的可能,所以如果能够减少使用的话,还是少用一些为好。

12.3.2 链式语法

链式语法的定义

在之前的例子(代码清单 12.1)中,事件侦听器的描述其实只用了 1 行,分号只是出现在最后的 appendTo() 方法的结尾处而已。在此之前全都是通过点运算符将方法连接起来的。为什么能够使用这样的书写方式呢?

jQuery 对象中的大部分方法都会返回一个 jQuery 对象。因此,如果执行了一个返回 jQuery 对象的方法,就能够对所返回的值再一次执行能返回 jQuery 对象的方法。以这种方式将方法连在一起书写的方式称为链式语法。

链式语法中的 jQuery 对象

需要注意的是,执行方法的 jQuery 对象与方法所返回的 jQuery 对象并不一定总是同一个对象。有时候会在方法内创建一个新的 jQuery 对象并将其返回。因此,如果只是简单地将链式方法拆开分行书写的话,并不一定能获得所期望的结果(代码清单 12.3)。为了使其正常执行功能,我们必须将目标对象替换为恰当的jQuery 对象(代码清单 12.4)。

可以通过在 jQuery 中更改所返回的 jQuery 对象来实现链式语法中操作对象的替换。在执行 find() 方法这样的用于对元素进行选择的方法时,可以替换目标元素集。而在执行了 end() 方法之后,所选中的元素集就会回到之前一次时的状态。通过使用 end() 方法,不但可以将目标元素集替换为恰当的值,还能够使
链式语法连得很长。不过,为了准确地运用 end() 方法,必须对之前的状态有着清楚的了解。否则就无法知道 end() 方法的返回值是以哪一个元素为目标的,从而无法执行期望的操作。以链式语法连起来书写的方式确实很方便,不过在书写时必须正确理解正在操作的对象才行。

代码清单 12.3 没有使用链式语法的不正确的书写方式
<!DOCTYPE html>
<html lang="zh">

<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>没有使用链式语法的不正确的书写方式</title>
    <script src="jquery-3.5.1.js"></script>
</head>

<body>
   <button class="hzh">点击该按钮时,添加一个链接</button>
   <button class="hzh">该按钮不会有反应</button>
   <script>
       // 不使用代码清单 12.1 中的链式语法来描述事件侦听器
       // 仅仅简单地对已有的对象依次执行方法并不得到所期望的执行得结果
       var elem = $('<div><a></a></div>');
       elem.find('a');                                 // 对 a 元素进行选择并不会将 elem 的引用替换为 a 元素 
       elem.text('www.huangzihan.top');                // 对 div 元素进行操作
       elem.attr('href', 'http://www.huangzihan.top'); // 对 div 元素进行的操作。无法生成链接
       elem.end();
       elem.appendTo('body');
   </script>
</body>

</html>

image

代码清单 12.4 没有使用链式语法的正确的书写方式
<!DOCTYPE html>
<html lang="zh">

<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>没有使用链式语法的正确的书写方式</title>
    <script src="jquery-3.5.1.js"></script>
</head>

<body>
   <button class="hzh">点击该按钮时,添加一个链接</button>
   <button class="hzh">该按钮不会有反应</button>
   <script>
       // 不使用代码清单 12.1 中的链式语法来描述事件侦听器
       // 由于同时以div元素与a这两个元素为目标进行处理,因此执行效果与所期待的一致
       var div = $('<div><a></a></div>');
       var a = div.find('a');
       a.text('www.huangzihan.top');                
       a.attr('href', 'http://www.huangzihan.top'); 
       // 如果没有使用链式语法,a.end()就没有意义了,所以不需要写出
       div.appendTo('body');
   </script>
</body>

</html>

image

专栏

链式语法的缺点

JavaScript 的主要功能之一为对 DOM 树中的元素进行选取与操作。在使用了 jQuery 之后,就能以非常简洁的书写方式实现对这一系列的处理的表述。不过,这种方便的链式语法也有其缺点。它存在调试时无法对其设定断点的问题。

开发者无法在链式语法连接起来的代码段中的特定位置设定断点。如果所写的代码没有复杂到不得不在调试时设定断点才能跟踪处理过程的话倒还好,但万一特别复杂的话,情况就会变得很麻烦。不过,最近出现了一些进化幅度令人惊讶的 JavaScript 调试器,如有可能,希望大家能尝试使用一下。

12.4 $函数

通过前面的例子我们可以知道,在 jQuery$ 函数(jQuery 函数)根据参数的不同可以执行各种操作。jQuery$ 函数将会根据当前的上下文语境选择最合适的操作。下面总结了 $ 函数的功能。

12.4.1 抽取与选择器相匹配的元素

在将 CSS 选择器传递给了 $ 函数之后,就能够抽取出与其相匹配的元素。而通过第 2 个参数还能够制定搜索范围。即使浏览器不支持在 CSS2 或 CSS3 中引入的选择器,也能够使用这一功能。

// 通过CSS选择器,从 id="foo" 的元素的子元素中抽取 class="bar" 的 div 元素
$('#foo div.bar');

// 同样是从 id="foo" 的元素的子元素中抽取出 class="bar" 的 div 元素
$('div.bar', '#foo');

// 以下面的方式指定参数也能获得相同的结果
var foo = document.getElementById('foo');
$('div.bar', foo);

另外,除了 CSS 选择器之外还能使用 jQuery 自定义的选择器。

12.4.2 创建新的 DOM 元素

如果将可以被解释为 html 标签的字符串传递给 $ 函数,则能够创建新的元素。

$('<div>新的div元素</div>')

12.4.3 将已有的 DOM 元素 转换为 jQuery 对象

如果将已有的 DOM 元素传递给 $ 函数,就能够将其转换为 jQuery 对象。

// 将 body 元素转换为 jQuery对象

$(document.body);

12.4.4 对 DOM 构造完成后的事件侦听器进行设定

如果把一个 Function 对象传递给 $ 函数,则能让该函数在 DOM 构造完成后执行。这与对 document 的 ready 事件设定事件侦听器的写法的效果是等价的。

12.5 通过jQuery进行DOM操作

12.5.1 元素的选择

表12.1 jQuery所能使用的选择器

可以通过 $ 函数选择元素。

image
image
image

表12.2 用于选择元素的方法

image
image

元素的index将被作为参数传递给函数。而函数内的this所引用的就是该 DOM 元素。

12.5.2 元素的创建·添加·替换·删除

可以通过 $ 函数来创建元素。另外,还可以通过 append() 方法同时执行元素的创建与添加。如果要进行替换操作,可以使用 replaceWith()等方法,如果要进行删除操作,则可以使用remove() 等方法。

表12.3 用于对元素进行操作的方法

image
image

12.6 通过jQuery处理事件

12.6.1 事件侦听器的注册·删除

bind()/unbind()

在 jQuery 中,我们可以通过 bind() 方法来注册事件侦听器。需要向该方法传递的是事件类型与事件侦听器。也可以传递事件类型与事件侦听器的映射,以同时注册多个事件侦听器。

而如果要删除事件侦听器,则可以使用 unbind()方法。需要向该方法的参数传递的是事件类型与函数。如果没有指定参数,则将删除元素中所有被设定的事件侦听器。在代码清单 12.5 中是 bind() 方法与 unbind() 方法的例子。

live()/die()

还可以通过 live() 方法来注册事件侦听器。其使用方式与 bind() 相同。

bind() 与 live() 的区别在于,通过 bind() 注册的事件侦听器只能对在执行 bind() 时已经存在的元素产生效果,而通过 live() 注册的事件侦听器则能对在执行了 bind() 之后才添加的元素也产生效果。之所以在事件侦听器被设定之后才添加的元素也能够受到事件侦听器的侦听,是因为 live() 是对 document 对象进行事件侦听器的设定的。对 document 对象设定的事件侦听器的处理流程是,首先检查冒泡阶段的事件,如果事件与 live() 所指定的选择器或事件类型相匹配,则将执行所注册的事件侦听器。

可以通过 die() 方法来解除通过 live() 设定的事件侦听器。这与 unbind() 的使用方法相同。

12.7 通过jQuery对样式进行操作

12.8 通过jQuery进行AJAX操作

12.9 Deferred

12.10 jQuery插件

12.11 与其他库共同使用

12.12 库的使用方法

posted @ 2022-05-15 17:35  黄子涵  阅读(4)  评论(0编辑  收藏  举报