当创建新元素(或选择现有元素)时,jQuery 会将这些元素作为一个集合返回。许多刚接触 jQuery 的开发者会误以为这个集合是一个数组。毕竟它具有零索引的 DOM 元素序列、一些熟悉的数组函数以及一个 .length 属性。实际上,jQuery 对象比这更复杂。
link DOM 和 DOM 元素
文档对象模型(简称 DOM)是 HTML 文档的一种表示形式。它可以包含任意数量的 DOM 元素。从高层次上看,DOM 元素可以被视为网页的“一块”。它可以包含文本和/或其他 DOM 元素。DOM 元素由类型(例如 <div>、<a> 或 <p>)以及任意数量的属性(例如 src、href、class 等)来描述。有关更详细的描述,请参阅 W3C 官方 DOM 规范。
元素具有属性,就像任何 JavaScript 对象一样。在这些属性中,包括像 .tagName 这样的特性(attributes)和像 .appendChild() 这样的方法。这些属性是唯一通过 JavaScript 与网页进行交互的方式。
link jQuery 对象
事实证明,直接使用 DOM 元素可能会很笨拙。jQuery 对象定义了 许多 方法来为开发者提供更顺畅的体验。jQuery 对象的一些优势包括:
兼容性 – DOM 方法的实现因浏览器厂商和版本而异。以下代码片段尝试设置存储在 target 中的 <tr> 元素的 inner HTML:
|
1
2
3
|
|
这在许多情况下有效,但在大多数版本的 Internet Explorer 中会失败。在这种情况下,推荐的方法 是使用纯 DOM 方法代替。通过将 target 元素包装在 jQuery 对象中,这些边界情况得到了处理,并在所有支持的浏览器中实现了预期的结果:
|
1
2
3
4
5
|
|
便利性 – 还有许多常见的 DOM 操作用例,使用纯 DOM 方法实现起来很笨拙。例如,要在 target 元素之后插入存储在 newElement 中的元素,需要一个相当冗长的 DOM 方法:
|
1
2
3
4
5
6
7
|
|
通过将 target 元素包装在 jQuery 对象中,相同的任务变得简单得多:
|
1
2
3
4
5
6
7
|
|
在大多数情况下,这些细节只是阻碍你实现目标的“陷阱”。
link 将元素放入 jQuery 对象中
当使用 CSS 选择器调用 jQuery 函数时,它将返回一个 jQuery 对象,该对象包装了匹配此选择器的所有元素。例如,编写:
|
1
2
3
|
|
headings 现在是一个 jQuery 对象,其中包含页面上已有的所有 <h1> 标签。可以通过检查 headings 的 .length 属性来验证这一点:
|
1
2
3
4
5
|
|
如果页面有多个 <h1> 标签,这个数字将大于一。如果页面没有 <h1> 标签,.length 属性将为零。检查 .length 属性是确保选择器成功匹配一个或多个元素的常用方法。
如果目标是只选择第一个标题元素,则需要额外的步骤。有多种方法可以实现这一点,但最直接的方法是使用 .eq() 函数。
|
1
2
3
4
5
|
|
现在 firstHeading 是一个 jQuery 对象,仅包含页面上的第一个 <h1> 元素。由于 firstHeading 是一个 jQuery 对象,它具有像 .html() 和 .after() 这样的有用方法。jQuery 还有一个名为 .get() 的方法,它提供了相关功能。它不是返回一个 jQuery 包装的 DOM 元素,而是返回 DOM 元素本身。
|
1
2
3
|
|
另外,由于 jQuery 对象是“类数组”的,它支持通过方括号进行数组下标访问:
|
1
2
3
|
|
无论哪种情况,firstHeadingElem 都包含原生的 DOM 元素。这意味着它具有像 .innerHTML 这样的 DOM 属性和像 .appendChild() 这样的方法,但没有 像 .html() 或 .after() 这样的 jQuery 方法。firstHeadingElem 元素处理起来更困难,但在某些情况下是必需的。其中一种情况是进行比较。
link 并非所有创建的 jQuery 对象都是 ===
关于这种“包装”行为的一个重要细节是,每个被包装的对象都是唯一的。即使对象是使用相同的选择器创建的或包含对完全相同的 DOM 元素的引用,情况也是如此。
|
1
2
3
4
|
|
尽管 logo1 和 logo2 是以相同方式创建的(并包装了相同的 DOM 元素),但它们不是同一个对象。例如:
|
1
2
3
|
|
然而,两个对象都包含相同的 DOM 元素。.get() 方法对于测试两个 jQuery 对象是否具有相同的 DOM 元素很有用。
|
1
2
3
4
5
6
7
8
9
|
|
许多开发者在包含 jQuery 对象的变量名称前加上 $ 前缀,以帮助区分。这种做法没有什么神奇之处——它只是帮助一些人跟踪不同变量包含的内容。前面的示例可以重写以遵循此约定:
|
1
2
3
4
5
6
7
8
9
|
|
此代码的功能与上面的示例相同,但阅读起来更清晰一些。
无论使用何种命名约定,区分 jQuery 对象和原生 DOM 元素都非常重要。原生 DOM 方法和属性在 jQuery 对象上不存在,反之亦然。像“event.target.closest is not a function”和“TypeError: Object [object Object] has no method 'setAttribute'”这样的错误消息表明存在这种常见的错误。
link jQuery 对象不是“实时”的
给定一个包含页面上所有段落元素的 jQuery 对象:
|
1
2
3
|
|
...人们可能会期望随着 <p> 元素被添加到文档中或从文档中删除,其内容会随时间增加和减少。jQuery 对象不以这种方式运行。jQuery 对象中包含的元素集不会改变,除非被明确修改。这意味着集合不是“实时”的——它不会随着文档的更改自动更新。如果自创建 jQuery 对象以来文档可能已更改,则应通过创建新对象来更新集合。这可以像重新运行相同的选择器一样简单:
|
1
2
3
|
|
link 总结
尽管 DOM 元素提供了创建交互式网页所需的所有功能,但使用它们可能会很麻烦。jQuery 对象包装这些元素以平滑这种体验并使常见任务变得容易。当使用 jQuery 创建或选择元素时,结果将始终包装在一个新的 jQuery 对象中。如果情况需要原生 DOM 元素,可以通过 .get() 方法和/或数组样式的下标来访问它们。