发布在:使用 jQuery Core

jQuery 对象

创建新元素(或选择现有元素)时,jQuery 会在集合中返回元素。许多刚接触 jQuery 的开发者会认为这个集合是一个数组。毕竟,它有一个从零开始的 DOM 元素序列、一些熟悉的数组函数和一个 .length 属性。实际上,jQuery 对象比这复杂得多。

链接 DOM 和 DOM 元素

文档对象模型(简称 DOM)是 HTML 文档的表示形式。它可能包含任意数量的 DOM 元素。从高层次上讲,DOM 元素可以被认为是网页的“一部分”。它可能包含文本和/或其他 DOM 元素。DOM 元素由类型描述,例如 <div><a><p>,以及任意数量的属性,例如 srchrefclass 等。如需更全面的描述,请参阅 W3C 的官方 DOM 规范

元素具有与任何 JavaScript 对象一样的属性。这些属性包括 .tagName 等属性和 .appendChild() 等方法。这些属性是通过 JavaScript 与网页交互的唯一途径。

链接 jQuery 对象

事实证明,直接使用 DOM 元素可能会很尴尬。jQuery 对象定义了 许多 方法,以改善开发人员的体验。jQuery 对象的一些好处包括

兼容性 – DOM 方法的实现因浏览器供应商和版本而异。以下代码段尝试设置存储在 target 中的 <tr> 元素的内部 HTML

1
2
3
var target = document.getElementById( "target" );
target.innerHTML = "<td>Hello <b>World</b>!</td>";

在许多情况下,这都能正常工作,但在大多数版本的 Internet Explorer 中会失败。在这种情况下,推荐的方法是改用纯 DOM 方法。通过将 target 元素包装在 jQuery 对象中,这些边缘情况得到了解决,并且在所有受支持的浏览器中都实现了预期结果

1
2
3
4
5
// Setting the inner HTML with jQuery.
var target = document.getElementById( "target" );
$( target ).html( "<td>Hello <b>World</b>!</td>" );

便利性 – 还有很多常见的 DOM 操作用例,使用纯 DOM 方法难以实现。例如,在 target 元素之后插入存储在 newElement 中的元素需要一个相当冗长的 DOM 方法

1
2
3
4
5
6
7
// Inserting a new element after another with the native DOM API.
var target = document.getElementById( "target" );
var newElement = document.createElement( "div" );
target.parentNode.insertBefore( newElement, target.nextSibling );

通过将 target 元素包装在 jQuery 对象中,同样的任务变得简单得多

1
2
3
4
5
6
7
// Inserting a new element after another with jQuery.
var target = document.getElementById( "target" );
var newElement = document.createElement( "div" );
$( target ).after( newElement );

在大多数情况下,这些细节只是阻碍您实现目标的“陷阱”。

链接 将元素放入 jQuery 对象

当使用 CSS 选择器调用 jQuery 函数时,它将返回一个 jQuery 对象,该对象包装与该选择器匹配的任何元素。例如,编写

1
2
3
// Selecting all <h1> tags.
var headings = $( "h1" );

headings 现在是一个 jQuery 对象,其中包含页面上已有的所有 <h1> 标签。可以通过检查 headings.length 属性来验证这一点

1
2
3
4
5
// Viewing the number of <h1> tags on the page.
var headings = $( "h1" );
alert( headings.length );

如果页面有多个 <h1> 标签,则此数字将大于 1。如果页面没有 <h1> 标签,则 .length 属性将为零。检查 .length 属性是确保选择器成功匹配一个或多个元素的常用方法。

如果目标是仅选择第一个标题元素,则需要执行另一步骤。有许多方法可以实现此目的,但最直接的方法是 .eq() 函数。

1
2
3
4
5
// Selecting only the first <h1> element on the page (in a jQuery object)
var headings = $( "h1" );
var firstHeading = headings.eq( 0 );

现在 firstHeading 是一个 jQuery 对象,其中仅包含页面上的第一个 <h1> 元素。并且由于 firstHeading 是一个 jQuery 对象,因此它具有 .html().after() 等有用的方法。jQuery 还有一个名为 .get() 的方法,它提供了一个相关函数。它不返回 jQuery 封装的 DOM 元素,而是返回 DOM 元素本身。

1
2
3
// Selecting only the first <h1> element on the page.
var firstHeadingElem = $( "h1" ).get( 0 );

或者,由于 jQuery 对象是“类似数组的”,因此它支持通过方括号进行数组下标

1
2
3
// Selecting only the first <h1> element on the page (alternate approach).
var firstHeadingElem = $( "h1" )[ 0 ];

在任一情况下,firstHeadingElem 都包含原生 DOM 元素。这意味着它具有 .innerHTML 等 DOM 属性和 .appendChild() 等方法,但没有 .html().after() 等 jQuery 方法。firstHeadingElem 元素更难操作,但在某些情况下需要使用它。其中一个情况就是进行比较。

链接 并非所有 jQuery 对象都创建 ===

关于这种“包装”行为的一个重要细节是,每个包装对象都是唯一的。即使使用相同的选择器创建对象或包含对完全相同的 DOM 元素的引用,这一点也是正确的。

1
2
3
4
// Creating two jQuery objects for the same element.
var logo1 = $( "#logo" );
var logo2 = $( "#logo" );

虽然 logo1logo2 是以相同的方式创建的(并且包装相同的 DOM 元素),但它们不是同一个对象。例如

1
2
3
// Comparing jQuery objects.
alert( $( "#logo" ) === $( "#logo" ) ); // alerts "false"

但是,这两个对象包含相同的 DOM 元素。.get() 方法可用于测试两个 jQuery 对象是否具有相同的 DOM 元素。

1
2
3
4
5
6
7
8
9
// Comparing DOM elements.
var logo1 = $( "#logo" );
var logo1Elem = logo1.get( 0 );
var logo2 = $( "#logo" );
var logo2Elem = logo2.get( 0 );
alert( logo1Elem === logo2Elem ); // alerts "true"

许多开发人员会在包含 jQuery 对象的变量名称前加上 $,以便于区分。这种做法并没有什么神奇之处——它只是帮助一些人跟踪不同变量包含的内容。前面的示例可以重写为遵循此约定

1
2
3
4
5
6
7
8
9
// Comparing DOM elements (with more readable variable names).
var $logo1 = $( "#logo" );
var logo1 = $logo1.get( 0 );
var $logo2 = $( "#logo" );
var logo2 = $logo2.get( 0 );
alert( logo1 === logo2 ); // alerts "true"

此代码的功能与上面的示例相同,但更易于阅读。

无论使用哪种命名约定,区分 jQuery 对象和原生 DOM 元素都非常重要。原生 DOM 方法和属性不存在于 jQuery 对象上,反之亦然。诸如“event.target.closest 不是函数”和“TypeError: Object [object Object] 没有 setAttribute 方法”之类的错误消息表明存在这种常见错误。

链接 jQuery 对象不是“实时”的

给定一个包含页面上所有段落元素的 jQuery 对象

1
2
3
// Selecting all <p> elements on the page.
var allParagraphs = $( "p" );

…人们可能会期望随着文档中添加和删除 <p> 元素,内容会随着时间的推移而增长和收缩。jQuery 对象不会以这种方式表现。包含在 jQuery 对象中的元素集合不会更改,除非明确修改。这意味着该集合不是“实时”的——它不会随着文档的更改而自动更新。如果文档在创建 jQuery 对象后可能已更改,则应通过创建一个新对象来更新该集合。这就像重新运行相同的选择器一样简单

1
2
3
// Updating the selection.
allParagraphs = $( "p" );

链接 总结

尽管 DOM 元素提供了创建交互式网页所需的所有功能,但使用起来可能很麻烦。jQuery 对象封装了这些元素,以简化此体验并使常见任务变得容易。使用 jQuery 创建或选择元素时,结果将始终封装在一个新的 jQuery 对象中。如果情况需要原生 DOM 元素,则可以通过 .get() 方法和/或数组式下标访问它们。