jQuery2 高级教程(二)
五、jQuery 基础知识
在这一章中,我将向你介绍你的第一个 jQuery 脚本。这个脚本很简单,但是它演示了 jQuery 的许多最重要的特性,包括如何在文档中选择元素、如何向您呈现这些选择,以及 jQuery 和内置 DOM API(HTML 规范的一部分)之间的关系的本质。表 5-1 对本章进行了总结。
表 5-1 。章节总结
| 问题 | 解决办法 | 列表 |
|---|---|---|
| 将 jQuery 添加到 HTML 文档。 | 使用link元素导入 jQuery 元素,链接到您的 web 服务器或 CDN。添加一个script元素来定义您的 jQuery 脚本。 | one |
| 动态选择 jQuery 1.x 或 2.x 行。 | 使用条件注释。 | Two |
| 选择文档中的元素。 | 将 CSS 选择器传递给$或jQuery函数。 | 3, 4, 10 |
重命名$功能。 | 使用noConflict方法。 | 5, 6 |
| 推迟 jQuery 脚本的执行,直到文档加载完毕。 | 在全局document变量上注册一个ready事件的处理程序,或者将一个函数传递给$函数。 | 7, 8 |
| 控制何时触发就绪事件。 | 使用holdReady事件。 | nine |
| 将元素选择限制在文档的一部分。 | 将上下文传递给$函数。 | 11, 12 |
确定用于创建jQuery对象的上下文。 | 读取context属性。 | Thirteen |
从HTMLElement对象创建一个jQuery对象。 | 将HTMLElement对象作为参数传递给$函数。 | Fourteen |
枚举一个jQuery对象的内容。 | 将jQuery对象视为数组或使用each方法。 | 15, 16 |
在jQuery元素中查找特定元素。 | 使用index或get方法。 | 17–19 |
| 对文档中的多个元素应用操作。 | 在jQuery对象上使用 jQuery 方法。 | Twenty |
对一个jQuery对象应用多个操作。 | 将方法调用链接在一起。 | 21–23 |
| 处理一个事件。 | 使用 jQuery 事件处理程序方法之一。 | Twenty-four |
JQUERY 自上一版以来发生了变化
在本书的第一版中,我描述了如何使用 selector属性从 jQuery 中获取一个选择器字符串,该字符串可用于将来的重复查询。从 jQuery 1.9 开始,selector属性已经被弃用,不应该再使用。
jQuery 1.9/2.0 使用的选择器引擎(称为 Sizzle )实现了对一些新的 CSS3 选择器的支持,即使在不支持它们的浏览器中。选择器有::nth-last-child、:nth-of-type、:nth-last-of-type、:first-of-type、:last-of-type、:only-of-type、:target、:root和:lang.
设置 jQuery
对于 jQuery,您需要做的第一件事是将它添加到想要处理的文档中。清单 5-1 显示了您在第一部分中第一次看到的花店示例文档,添加了 jQuery 库。
清单 5-1 。花店示例文档
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<link rel="stylesheet" type="text/css" href="styles.css"/>
<script src="jquery-2.0.2.js" type="text/javascript"></script>
</head>
<body>
<h1>Jacqui's Flower Shop</h1>
<form method="post">
<div id="oblock">
<div class="dtable">
<div id="row1" class="drow">
<div class="dcell">
<img src="aster.png"/><label for="aster">Aster:</label>
<input name="aster" value="0" required>
</div>
<div class="dcell">
<img src="daffodil.png"/><label for="daffodil">Daffodil:</label>
<input name="daffodil" value="0" required >
</div>
<div class="dcell">
<img src="rose.png"/><label for="rose">Rose:</label>
<input name="rose" value="0" required>
</div>
</div>
<div id="row2" class="drow">
<div class="dcell">
<img src="peony.png"/><label for="peony">Peony:</label>
<input name="peony" value="0" required>
</div>
<div class="dcell">
<img src="primula.png"/><label for="primula">Primula:</label>
<input name="primula" value="0" required>
</div>
<div class="dcell">
<img src="snowdrop.png"/><label for="snowdrop">Snowdrop:</label>
<input name="snowdrop" value="0" required>
</div>
</div>
</div>
</div>
<div id="buttonDiv"><button type="submit">Place Order</button></div>
</form>
</body>
</html>
为了帮助保持对内容的关注,我将 CSS 样式移到了一个单独的样式表中,名为 styles.css,如第三章所示。您可以看到我是如何将 jQuery 库添加到文档的,如下所示:
...
<script src="jquery-2.0.2.js" type="text/javascript"></script>
...
一旦您选择了将要使用的 jQuery 行(1.x 或 2.x 行,如第三章中的所述),您将从jquery.com中选择两个文件——一个文件扩展名为.js,另一个文件扩展名为.min.js。对于我写这篇文章时的 2.x 行版本,这些文件被称为jquery-2.0.2.js和jquery-2.0.2.min.js。
jquery-2.0.2.js文件是在网站或应用开发过程中通常使用的文件。这个文件大约 240KB,是标准的 JavaScript 代码。您可以打开并阅读该文件,了解 jQuery 是如何实现其特性的,并在代码中遇到问题时使用浏览器调试器来找出问题所在。
提示 jQuery 正在积极开发中,所以当你读到这篇文章时,一个更新的版本几乎肯定已经发布了。但是不要担心——尽管有很多不推荐的方法和分裂的开发路线,jQuery API 非常稳定,并且随着 jQuery 1.x 和 2.x 的不断成熟,我在本书中展示的所有技术都将继续发挥作用。
另一个文件jquery.2.0.2.min.js,是为用户部署站点或 web 应用时使用的。它包含相同的 JavaScript 代码,但是被缩减为,这意味着所有的空白字符都被删除,有意义的变量名被替换为单字符名称以节省空间。为了调试的目的,缩小的脚本几乎无法阅读,但是它要小得多。缩小过程将文件大小减少到大约 82KB,如果您提供大量依赖 jQuery 的页面,那么这种差异可以为您节省大量带宽。
提示你可以从
jquery.com下载一个源地图(扩展名为.min.map)。源代码映射允许简化的代码更容易调试。它们是一个新的想法,在我写这篇文章的时候还没有被广泛实现。你可以在http://www.html5rocks.com/en/tutorials/developertools/sourcemaps看到一个简单的演示。
为 JQUERY 使用 CDN
将 jQuery 库存储在您自己的 web 服务器上的另一种方法是使用一个托管 jQuery 的公共 内容交付网络 (CDN) 。CDN 是一个由服务器组成的分布式网络,使用离用户最近的服务器向用户交付文件。使用 CDN 有几个好处。首先是用户体验更快,因为 jQuery 库文件是从离他们最近的服务器上下载的,而不是从您的服务器上。通常根本不需要下载:jQuery 如此受欢迎,以至于用户的浏览器可能已经从另一个使用 jQuery 的应用或网站缓存了这个库。第二个好处是没有任何带宽用于向用户交付 jQuery。对于高流量的网站来说,这可以节省大量的成本。
使用 CDN 的时候,一定要对 CDN 运营商有信心。您希望确保用户收到他们应该收到的文件,并且服务将始终可用。谷歌和微软都免费为 jQuery(以及其他流行的 JavaScript 库)提供 CDN 服务。两家公司都有运行高可用性服务的良好经验,不太可能故意篡改 jQuery 库。你可以在www.asp.net/ajaxlibrary/cdn.ashx了解微软服务,在http://code.google.com/apis/libraries/devguide.html了解谷歌服务。
CDN 方法不适合在内部网中交付给用户的应用,因为它会导致所有浏览器都通过互联网来获取 jQuery 库,而不是访问本地服务器,后者通常更近、更快、带宽成本更低。
使用条件注释
在清单 5-1 中,我只包含了版本 2.0.2 的 jQuery 库。这个版本提供了最好的性能,但它不支持旧版本的 Internet Explorer,如第一章所述。
好消息是,您不必在性能和兼容性之间做出选择。有一种技术可以自动在 1.x 和 2.x jQuery 库之间进行动态选择,使用一种称为条件注释的功能,这是微软为 Internet Explorer 5 创建的 HTML 的非标准增强。在清单 5-2 中,您可以看到我是如何将条件注释特性应用到示例 HTML 文档中的。
清单 5-2 。使用条件注释在 jQuery 1.x 和 2.x 之间进行动态选择
...
<head>
<title>Example</title>
<link rel="stylesheet" type="text/css" href="styles.css"/>
<!--[if lt IE 9]>
<script src="jquery-1.10.1.js" type="text/javascript"></script>
<![endif]-->
<!--[if gte IE 9]><!-->
<script src="jquery-2.0.2.js" type="text/javascript"></script>
<!--<![endif]-->
</head>
...
条件注释将为 Internet Explorer 9 之前的版本加载 jQuery 1.10.1,为所有其他浏览器加载 jQuery 2.0.2。你应该注意准确地复制这些评论——很容易出错。
提示我不打算在本书中深入讨论条件注释,但你可以在
http://en.wikipedia.org/wiki/Conditional_comment了解更多。
第一个 jQuery 脚本
现在我已经将 jQuery 库添加到了文档中,我可以编写一些使用 jQuery 功能的 JavaScript 了。清单 5-3 包含一个简单的script元素,展示了一些基本的 jQuery 特性。
清单 5-3 。第一个 jQuery 脚本
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<link rel="stylesheet" type="text/css" href="styles.css"/>
<script src="jquery-2.0.2.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$("img:odd").mouseenter(function (e) {
$(this).css("opacity", 0.5);
}).mouseout(function (e) {
$(this).css("opacity", 1.0);
});
});
</script>
</head>
<body>
<h1>Jacqui's Flower Shop</h1>
<form method="post">
<div id="oblock">
<div class="dtable">
<div id="row1" class="drow">
<div class="dcell">
<img src="aster.png"/><label for="aster">Aster:</label>
<input name="aster" value="0" required>
</div>
<div class="dcell">
<img src="daffodil.png"/><label for="daffodil">Daffodil:</label>
<input name="daffodil" value="0" required >
</div>
<div class="dcell">
<img src="rose.png"/><label for="rose">Rose:</label>
<input name="rose" value="0" required>
</div>
</div>
<div id="row2" class="drow">
<div class="dcell">
<img src="peony.png"/><label for="peony">Peony:</label>
<input name="peony" value="0" required>
</div>
<div class="dcell">
<img src="primula.png"/><label for="primula">Primula:</label>
<input name="primula" value="0" required>
</div>
<div class="dcell">
<img src="snowdrop.png"/><label for="snowdrop">Snowdrop:</label>
<input name="snowdrop" value="0" required>
</div>
</div>
</div>
</div>
<div id="buttonDiv"><button type="submit">Place Order</button></div>
</form>
</body>
</html>
这是一个简短的脚本,但是它展示了 jQuery 的一些最重要的特性和特征。在这一章中,我将一行一行地分解这个脚本,但是这本书的其余部分将会让你完全理解这个脚本所涉及的所有功能领域。首先,图 5-1 显示了这个脚本创建的效果。
图 5-1 。更改图像不透明度
提示您会注意到,我已经在清单中返回到了 jQuery 2.0.2 的显式使用——我将在本书的其余大部分中这样做。我想让例子简单明了,但是我建议您使用条件注释技术,我发现这在我自己的项目中很有用。
当鼠标移动到水仙花、牡丹和雪花莲图像上时,该脚本会改变它们的不透明度。这具有使图像看起来更亮和褪色的效果。当鼠标离开图像时,不透明度会恢复到其先前的值。紫菀、玫瑰和报春花的图像不受影响。
了解 jQuery $函数
您可以通过$(...)函数访问 jQuery,为了简单起见,我将它称为 *函数是 jQuery 奇妙世界的入口点,也是jQuery`函数的简写。如果您愿意,您可以重写示例脚本以使用完整的函数名,如清单 5-4 所示。
清单 5-4 。使用 jQuery 函数代替简写
...
<script type="text/javascript">
jQuery(document).ready(function () {
jQuery("img:odd").mouseenter(function(e) {
jQuery(this).css("opacity", 0.5);
}).mouseout(function(e) {
jQuery(this).css("opacity", 1.0);
});
});
</script>
...
该脚本提供了与上一个示例相同的功能。它需要的输入稍微多一点,但是它的优点是可以显式地使用 jQuery。
这可能很有用,因为 jQuery 不是唯一使用$符号的 JavaScript 库,当您在同一个文档中使用多个库时,这可能会导致问题。您可以通过调用jQuery.noConflict方法让 jQuery 放弃对$的控制,如清单 5-5 中的所示。
清单 5-5 。释放 jQuery 对$的控制
...
<script type="text/javascript">
jQuery.noConflict();
jQuery(document).ready(function () {
jQuery("img:odd").mouseenter(function(e) {
jQuery(this).css("opacity", 0.5);
}).mouseout(function(e) {
jQuery(this).css("opacity", 1.0);
});
});
</script>
...
您也可以定义自己的速记符号。你可以通过将noConflict方法的结果赋给一个变量来实现,如清单 5-6 所示。
清单 5-6 。使用另一种速记法
...
<script type="text/javascript">
var jq = jQuery.noConflict();
jq(document).ready(function () {
jq("img:odd").mouseenter(function(e) {
jq(this).css("opacity", 0.5);
}).mouseout(function(e) {
jq(this).css("opacity", 1.0);
});
});
</script>
...
在这个例子中,我创建了自己的速记,jq,然后在我的脚本的其余部分使用这个速记。
提示我将在本书中通篇使用
$符号,因为这是 jQuery 的常规约定(也因为我不会使用任何其他想要控制$的库)。
不管你如何引用主jQuery函数,你都可以传递相同的一组参数,其中最重要的我已经在表 5-2 中描述过了。所有这些论点都将在本章后面描述,除了最后一个,它将在第七章中描述。
表 5-2 。主 jQuery 函数的参数
| 争吵 | 描述 |
|---|---|
$(function) | 指定当 DOM 准备好时要执行的函数。 |
$(selector) $(selector, context) | 从文档中选择元素。 |
$(HTMLElement) $(HTMLElement[]) | 从一个HTMLElement或一组HTMLElement对象创建一个 jQuery 对象。 |
$() | 创建一个空选择。 |
$(HTML) $(HTML, map) | 使用可选的 map 对象从 HTML 片段创建新元素来定义属性。详见第七章。 |
等待文档对象模型
在第二章的中,我将script元素放在了文档的末尾,这样浏览器在执行我的 JavaScript 代码之前就会在 DOM 中创建所有的对象。通过使用 jQuery,通过使用下面的技术,您可以巧妙地避免这个问题:
...
<script type="text/javascript">
$(document).ready(function () {
// ...
*code to execute*...
});
</script>
...
我没有将 JavaScript 语句直接放在script元素中,而是将document对象(我在《??》第一章中介绍过)传递给了$函数,并调用了ready方法,传递了一个我希望只有当浏览器加载完 HTML 文档中的所有内容时才执行的函数。清单 5-7 显示了我如何在示例 HTML 文档中应用这一技术。
清单 5-7 。等待 DOM
...
<script type="text/javascript">
$(document).ready(function () {
$("img:odd").mouseenter(function (e) {
$(this).css("opacity", 0.5);
}).mouseout(function (e) {
$(this).css("opacity", 1.0);
});
});
</script>
...
使用 ready函数意味着我可以将script元素放在 HTML 文档中我想要的任何地方,因为 jQuery 会防止函数过早执行。我喜欢把我的script元素放在 HTML 文档的head元素中,但这只是我的偏好。
注意向
ready方法传递一个function会为 jQuery ready事件创建一个处理程序。我在第九章中全面介绍了 jQuery 事件。目前,请接受这样的事实:当文档被加载并且 DOM 准备好可以使用时,您传递给ready方法的function将被调用。
忘记功能
一个常见的错误是省略这个咒语的function部分,只将一系列 JavaScript 语句传递给ready方法。这是行不通的,浏览器会立即执行这些语句,而不是在 DOM 准备好的时候。考虑以下脚本:
...
<script type="text/javascript">
function countImgElements() {
return $("img").length;
}
$(document).ready(function() {
console.log("Ready function invoked. IMG count: " + countImgElements());
});
$(document).ready(
console.log("Ready statement invoked. IMG count: " + countImgElements())
);
</script>
我调用了两次ready方法,一次用了一个function,另一次只是传入了一个常规的 JavaScript 语句。在这两种情况下,我都调用了 countImgElements函数,该函数返回 DOM 中存在的img元素的数量。(暂时不要担心这个方法如何运作。我将在本章后面解释对length属性的调用。)当我加载文档时,脚本被执行,以下输出被写入控制台:
Ready statement invoked. IMG count: 0
正如您所看到的,在加载文档时,在浏览器发现文档中的img元素并创建相应的 DOM 对象之前,执行没有函数的语句。
使用替代符号
如果愿意,可以将函数作为参数传递给 jQuery $函数。这与使用$(document).ready方法具有相同的效果。清单 5-8 提供了一个演示。
清单 5-8 。推迟函数的执行,直到 DOM 准备好
...
<script type="text/javascript">
$(function() {
$("img:odd").mouseenter(function(e) {
$(this).css("opacity", 0.5);
}).mouseout(function(e) {
$(this).css("opacity", 1.0);
})
});
</script>
...
推迟就绪事件
您可以通过使用holdReady方法来控制何时触发ready事件。如果您需要动态加载外部资源(一种不常见的高级技术),这可能会很有用。在触发ready事件之前,必须调用holdReady方法,当您准备好时,可以再次调用该方法。清单 5-9 给出了一个使用这种方法的例子。
清单 5-9 。使用保持就绪方法
...
<script type="text/javascript">
$.holdReady(true);
$(document).ready(function() {
console.log("Ready event triggered");
$("img:odd").mouseenter(function(e) {
$(this).css("opacity", 0.5);
}).mouseout(function(e) {
$(this).css("opacity", 1.0);
})
});
setTimeout(function() {
console.log("Releasing hold");
$.holdReady(false);
}, 5000);
</script>
...
我在script元素的开头调用了holdReady方法,传入true作为参数,表示我希望举行ready事件。然后我定义了当ready事件被触发时我希望被调用的函数(这是我打开这一章时使用的同一套语句,它改变了一些图像的不透明度)。
最后,我使用setTimeout方法在五秒钟后调用一个函数。这个函数调用带有参数false的holdReady方法,它告诉 jQuery 触发ready事件。最终结果是我将ready事件延迟了五秒钟。我添加了一些调试消息,当文档加载到浏览器中时,这些消息会将以下输出写入控制台:
Releasing hold
Ready event triggered
提示你可以多次调用
holdReady方法,但是在ready事件被触发之前,带有true参数的holdReady方法的调用次数必须与带有false参数的调用次数相等。
选择元素
jQuery 功能最重要的一个方面是如何从 DOM 中选择元素。在示例脚本中,我定位了所有的奇数 img元素,如清单 5-10 中的所示。
清单 5-10 。从 DOM 中选择元素
...
<script type="text/javascript">
$(document).ready(function() {
$("img:odd").mouseenter(function(e) {
$(this).css("opacity", 0.5);
}).mouseout(function(e) {
$(this).css("opacity", 1.0);
})
});
</script>
...
要选择元素,只需将选择器传递给$函数。jQuery 支持我在第三章中描述的所有 CSS 选择器,加上一些额外的选择器,这些选择器给你一些方便的细粒度控制。在这个例子中,我使用了:odd伪选择器,它选择与选择器主要部分匹配的奇数元素(在这个例子中是img,它选择所有的img元素,如第三章所述)。:odd选择器是从零开始的,这意味着第一个元素被认为是偶数。一开始可能会有点困惑。表 5-3 列出了最有用的 jQuery 选择器。
表 5-3 。jQuery 扩展选择器
| 选择器 | 描述 |
|---|---|
:animated | 选择所有正在制作动画的元素。 |
:contains(text) | 选择包含指定文本的元素。 |
:eq(n) | 选择第n个索引处的元素(从零开始)。 |
:even | 选择所有事件编号的元素(从零开始)。 |
:first | 选择第一个匹配的元素。 |
:gt(n) | 选择索引大于n(从零开始)的所有元素。 |
:has(selector) | 选择至少包含一个与指定选择器匹配的元素的元素。 |
:last | 选择最后匹配的元素。 |
:lt(n) | 选择索引小于n(从零开始)的所有元素。 |
:odd | 选择所有奇数元素(从零开始)。 |
:text | 选择所有文本元素。 |
提示你可以通过调用不带任何参数的
$函数($())来创建一个空的选择。我提到这一点是为了完整性,但这并不是我曾经有理由使用的一个特性。
我称之为最有用的,因为它们定义了使用 CSS 选择器很难重新创建的功能。这些选择器就像 CSS 伪选择器一样使用。它们可以单独使用,在这种情况下,它们应用于 DOM 中的所有元素,如下所示:
...
$(":even")
...
或者与其他选择器组合以缩小选择范围,如下所示:
...
$("img:even")
...
jQuery 还定义了基于类型选择元素的选择器,如表 5-4 所述。
表 5-4 。jQuery 类型扩展选择器
| 选择器 | 描述 |
|---|---|
:button | 选择所有按钮。 |
:checkbox | 选中所有复选框。 |
:file | 选择所有文件元素。 |
:header | 选择所有标题元素(h1、h2等)。 |
:hidden | 选择所有隐藏元素。 |
:image | 选择所有图像元素。 |
:input | 选择所有输入元素。 |
:last | 选择最后匹配的元素。 |
:parent | 选择其他元素的所有父元素。 |
:password | 选择所有密码元素。 |
:radio | 选择所有单选按钮。 |
:reset | 选择重置表单的所有元素。 |
:selected | 选择所有选定的元素。 |
:submit | 选择所有表单提交元素。 |
:visible | 选择所有可见元素。 |
考虑选择器性能
如果您花时间阅读 jQuery,您肯定会遇到关于选择器性能的讨论。许多人花费大量时间比较不同的选择器表达方式,以最大限度地发挥 jQuery 的性能。
我的观点很简单:这不应该有关系——如果有关系,那就是其他问题的迹象。jQuery 的性能非常好,尤其是在最新版本的主流浏览器上,这些浏览器具有快速的 JavaScript 实现。当我看到项目团队试图优化选择器性能时,通常是因为他们正在处理大量的 HTML 元素,在这些元素中,执行一个选择需要数百毫秒——当执行一个操作需要几个这样的选择时,我们开始进入用户注意到的延迟长度。
真正的问题不是 jQuery——而是向浏览器发送的内容超出了合理预期的范围。浏览器的功能越来越强大,但是它们的功能是有限的,尤其是老版本的浏览器和运行在移动设备上的浏览器。
如果你发现自己很难足够快地选择元素,不要试图优化选择器的使用。相反,重新考虑你对 HTML 元素的使用:想办法尽量减少发送到浏览器的内容,在服务器上承担一些处理工作,不要把 web 应用当作桌面应用。
用上下文缩小选择范围
默认情况下,jQuery 在整个 DOM 中搜索元素,但是您可以通过向$函数提供一个额外的参数来缩小选择范围。这给了搜索一个上下文,它被用作匹配元素的起点,如清单 5-11 所示。
清单 5-11 。使用上下文缩小搜索范围
...
<script type="text/javascript">
$(document).ready(function() {
$("img:odd",$(".drow")).mouseenter(function(e) {
$(this).css("opacity", 0.5);
}).mouseout(function(e) {
$(this).css("opacity", 1.0);
})
});
</script>
...
在这个例子中,我使用一个 jQuery 选择作为另一个的上下文。首先评估上下文,它匹配所有属于drow类的元素。这组元素然后被用作img:odd选择器的上下文。
当您提供包含多个元素的上下文时,每个元素都被用作搜索的起点。这种方法有一个有趣的微妙之处。匹配上下文的元素被收集在一起,然后执行主选择。在本例中,这意味着img:odd选择器应用于drow选择器的结果,这意味着奇数编号的元素与搜索整个文档时的元素不同。最终结果是不透明效果被应用到drow类的每个div元素中奇数编号的img元素,选择水仙花和报春花图像。当我在前面的例子中省略上下文时,效果被应用到水仙花、牡丹和雪花莲图像上。
如果您只想匹配文档中从给定点开始的元素,那么您可以使用一个HTMLElement对象作为上下文。清单 5-12 包含了一个例子。在下一节中,我将向您展示如何在 jQuery 世界和HTMLElement对象之间轻松切换。
清单 5-12 。使用 HTMLElement 作为上下文
...
<script type="text/javascript">
$(document).ready(function() {
var elem = document.getElementById("oblock");
$("img:odd",elem).mouseenter(function(e) {
$(this).css("opacity", 0.5);
}).mouseout(function(e) {
$(this).css("opacity", 1.0);
})
});
</script>
...
本例中的脚本搜索奇数编号的img元素,将搜索限制在那些从id为oblock的元素派生的元素。
当然,使用后代 CSS 选择器也可以达到同样的效果。当您希望以编程方式缩小搜索范围,而不必构造选择器字符串时,这种方法的好处就显现出来了。这种情况的一个很好的例子是在处理事件时。你可以在第九章的中了解更多关于事件的信息(并看看HTMLElement物体在这种情况下是如何出现的)。
了解选择结果
当您使用 jQuery 从 DOM 中选择元素时,$函数的结果是一个容易混淆的名称为jQuery的对象,它表示零个或多个 DOM 元素。事实上,当您执行一个修改一个或多个元素的 jQuery 操作时,结果很可能是一个jQuery对象,这是一个重要的特征,我将很快返回。
由 jQuery 对象定义的方法和属性基本上是本书其余部分的内容,但我可以在本章中介绍一些基本成员,如表 5-5 中所述。
表 5-5 。基本 jQuery 对象成员
| 选择器 | 描述 | 返回 |
|---|---|---|
context | 返回用作搜索上下文的元素集。 | HTMLElement |
each(function) | 对每个选定的元素执行该功能。 | jQuery |
get(index) | 获取指定索引处的HTMLElement对象。 | HTMLElement |
index(HTMLElement) | 返回指定HTMLElement.的索引 | number |
index(jQuery) | 返回jQuery对象中第一个元素的索引。 | number |
index(selector) | 返回选择器匹配的元素集中第一个元素在jQuery对象中的索引 | number |
length | 返回jQuery对象包含的元素数量。 | number |
size() | 返回jQuery对象中元素的数量。 | number |
toArray() | 以数组形式返回由jQuery对象包含的HTMLElement对象。 | HTMLElement[] |
确定上下文
context 属性提供了创建 jQuery 时使用的上下文的详细信息。如果单个HTMLElement对象被用作上下文,那么 context 属性将返回那个HTMLElement。如果没有使用上下文或者使用了多个元素(如我在本章前面使用的例子),那么上下文属性返回undefined。清单 5-13 展示了这个属性的使用。
清单 5-13 。确定 jQuery 对象的上下文
...
<script type="text/javascript">
$(document).ready(function() {
var jq1 = $("img:odd");
console.log("No context: " +jq1.context.tagName);
var jq2 = $("img:odd", $(".drow"));
console.log("Multiple context elements: " +jq2.context.tagName);
var jq3 = $("img:odd", document.getElementById("oblock"));
console.log("Single context element: " +jq3.context.tagName);
});
</script>
...
该脚本选择不使用上下文、多个上下文对象和单个上下文对象的元素。输出如下所示:
No context: undefined
Multiple context elements: undefined
Single context element: DIV
处理 DOM 对象
jQuery 并没有取代 DOM 这让工作变得容易多了。还在使用HTMLElement对象(我在第二章中介绍过),jQuery 库使得在jQuery对象和 DOM 对象之间切换变得很容易。您可以轻松地从传统的 DOM 迁移到 jQuery,这是 jQuery 优雅的一部分,有助于保持与非 jQuery 脚本和库的兼容性。
从 DOM 对象创建 jQuery 对象
您可以通过将一个HTMLElement对象或一组HTMLElement对象作为参数传递给$函数来创建jQuery对象。这在处理不是用 jQuery 编写的 JavaScript 代码时,或者在 jQuery 公开底层 DOM 对象的情况下,比如事件处理,会很有用。清单 5-14 包含了一个例子。
清单 5-14 。从 DOM 对象创建 jQuery 对象
...
<script type="text/javascript">
$(document).ready(function() {
var elems = document.getElementsByTagName("img");
$(elems).mouseenter(function(e) {
$(this).css("opacity", 0.5);
}).mouseout(function(e) {
$(this).css("opacity", 1.0);
})
});
</script>
...
在这个例子中,我使用document.getElementsByTagName方法选择文档中的img元素,而不是直接使用带有选择器的 jQuery。我将这个方法的结果(它是一个HTMLElement对象的集合)传递给$函数,该函数返回一个常规的jQuery对象,我可以像前面的例子一样使用它。
这个脚本还演示了如何从单个HTMLElement对象创建一个 jQuery 对象:
...
$(this).css("opacity", 1.0);
...
当您处理事件时,jQuery 将变量this的值设置为正在处理事件的HTMLElement。我在第九章中描述了 jQuery 事件支持,所以我不想在本章深入讨论这个主题(尽管我在本章稍后会再次提到包含这些语句的函数)。
将 jQuery 对象视为数组
您可以将一个jQuery对象视为一组HTMLElement对象。这意味着您可以使用 jQuery 提供的高级特性,但仍然可以直接访问 DOM。您可以使用length属性或size方法来确定在jQuery对象中收集了多少元素,并通过使用数组样式的索引(使用[和]括号)来访问单个 DOM 对象。
提示你可以使用
toArray方法从jQuery对象中提取HTMLElement对象作为数组。我喜欢使用jQuery对象本身,但有时使用 DOM 对象也很有用,比如在处理不是用 jQuery 编写的遗留代码时。
清单 5-15 展示了如何枚举一个 jQuery 对象的内容来访问其中包含的HTMLElement对象。
清单 5-15 。将 jQuery 对象视为数组
...
<script type="text/javascript">
$(document).ready(function() {
var elems = $("img:odd");
for (var i = 0; i < elems.length; i++) {
console.log("Element: " + elems[i].tagName + " " + elems[i].src);
}
});
</script>
...
在清单中,我使用$函数选择奇数编号的img元素,并枚举所选元素以将tagName和src属性的值打印到控制台。结果如下:
Element: IMGhttp://www.jacquisflowershop.com/jquery/daffodil.png
Element: IMGhttp://www.jacquisflowershop.com/jquery/peony.png
Element: IMGhttp://www.jacquisflowershop.com/jquery/snowdrop.png
在 DOM 对象上迭代一个函数
each方法允许您为 jQuery 对象中的每个 DOM 对象定义一个函数。清单 5-16 给出了一个演示。
清单 5-16 。使用 each 方法
...
<script type="text/javascript">
$(document).ready(function() {
$("img:odd").each(function(index, elem) {
console.log("Element: " + elem.tagName + " " + elem.src);
});
});
</script>
...
jQuery 向指定的函数传递两个参数。第一个是集合中元素的索引,第二个是元素对象本身。在本例中,我将标记名和src属性的值写入控制台,产生与前面脚本相同的结果:
Element: IMGhttp://www.jacquisflowershop.com/jquery/daffodil.png
Element: IMGhttp://www.jacquisflowershop.com/jquery/peony.png
Element: IMGhttp://www.jacquisflowershop.com/jquery/snowdrop.png
查找索引和特定元素
index方法允许您在 jQuery 对象中查找HTMLElement的索引。您可以使用HTMLElement或jQuery对象作为参数来传递您想要的索引。当您使用一个jQuery对象时,第一个匹配的元素是其索引被返回的元素。清单 5-17 给出了一个演示。
清单 5-17 。定位 HTMLElement 的索引
...
<script type="text/javascript">
$(document).ready(function() {
var elems = $("body *");
// find an index using the basic DOM API
var index = elems.index(document.getElementById("oblock"));
console.log("Index using DOM element is: " + index);
// find an index using another jQuery object
index = elems.index($("#oblock"));
console.log("Index using jQuery object is: " + index);
});
</script>
...
在这个例子中,我使用 DOM API 的getElementById方法找到一个方法,通过id属性值找到一个div元素。这将返回一个HTMLElement对象。然后我在一个jQuery对象上使用index方法来查找代表div元素的对象的索引。我使用一个通过$函数获得的jQuery对象重复这个过程。我将两种方法的结果写入控制台,控制台产生以下结果:
Index using DOM element is: 2
Index using jQuery object is: 2
您也可以将一个string传递给index方法。当你这样做的时候,string被解释为一个选择器。然而,这种方法导致index方法的行为方式与前面的例子不同。清单 5-18 提供了一个演示。
清单 5-18 。使用索引方法的选择器版本
...
<script type="text/javascript">
$(document).ready(function() {
var imgElems = $("img:odd");
// find an index using a selector
index = imgElems.index("body *");
console.log("Index using selector is: " + index);
// perform the same task using a jQuery object
index = $("body *").index(imgElems);
console.log("Index using jQuery object is: " + index);
});
</script>
...
当您将一个string传递给index方法时,元素集合的使用顺序会改变。jQuery 使用选择器匹配元素,然后返回 jQuery 对象中第一个元素的匹配元素的索引,在该 jQuery 对象上调用了 index 方法。这意味着这种说法:
...
index = imgElems.index("body *");
...
相当于这个语句:
...
index = $("body *").index(imgElems);
...
本质上,传递字符串参数颠倒了两组元素的考虑方式。该列表产生以下结果:
Index using selector is: 10
Index using jQuery object is: 10
提示我们可以使用没有参数的
index方法来获得一个元素相对于它的兄弟元素的位置。这在使用 jQuery 探索 DOM 时会很有用,这是《??》第七章的主题。
get方法是对index方法的补充,这样您可以指定一个索引并在 jQuery 对象中的该位置接收HTMLElement对象。这与我在本章前面描述的使用数组风格的索引有相同的效果。清单 5-19 提供了一个演示。
清单 5-19 。获取给定索引处的 HTMLElement 对象
...
<script type="text/javascript">
$(document).ready(function() {
var elem = $("img:odd").get(1);
console.log("Element: " + elem.tagName + " " + elem.src);
});
</script>
...
在这个脚本中,我选择奇数编号的img元素,使用get方法检索索引 1 处的HTMLElement对象,并将tagName和src属性的值写入控制台。该脚本的输出如下:
Element: IMGhttp://www.jacquisflowershop.com/jquery/peony.png
修改多个元素和链接方法调用
jQuery 如此简洁和富有表现力的一个特性是,调用一个jQuery对象上的方法通常会修改该对象包含的所有元素。我说通常是,因为有些方法执行不适用于多个元素的操作,你会在后面的章节看到这样的例子。清单 5-20 展示了如何使用 DOM API 对多个元素执行操作。
清单 5-20 。使用 DOM API 对多个元素进行操作
...
<script type="text/javascript">
$(document).ready(function() {
var labelElems = document.getElementsByTagName("label");
for (var i = 0; i < labelElems.length; i++) {
labelElems[i].style.color = "blue";
}
});
</script>
...
script元素中的语句选择所有的label元素,并将 CSS color属性的值设置为blue。清单 5-21 展示了如何使用 jQuery 执行同样的任务。
清单 5-21 。使用 jQuery 对多个元素进行操作
...
<script type="text/javascript">
$(document).ready(function () {
$("label").css("color", "blue");
});
</script>
...
我可以使用一条 jQuery 语句来执行这项任务,这比使用 DOM API 要简单得多——我承认这不是一个很大的区别,但是它可以安装在一个复杂的 web 应用中。jQuery 语句也更容易阅读和理解,这有助于 JavaScript 代码的长期维护。
对象的另一个很好的特性是它实现了一个流畅的 API ??。这意味着无论何时调用修改对象内容的方法,该方法的结果都是另一个 jQuery 对象。这看起来很简单,但是它允许你执行方法链接,如清单 5-22 所示。
清单 5-22 。jQuery 对象上的方法链接方法调用
...
<script type="text/javascript">
$(document).ready(function() {
$("label").css("color", "blue").css("font-size", ".75em");
var labelElems = document.getElementsByTagName("label");
for (var i = 0; i < labelElems.length; i++) {
labelElems[i].style.color = "blue";
labelElems[i].style.fontSize = ".75em";
}
});
</script>
...
在这个例子中,我使用$函数创建一个 jQuery 对象,调用css方法为color属性设置一个值,然后再次调用css方法,这次是为了设置font-size属性。我还展示了使用基本 DOM API 的等效添加。您可以看到,要达到同样的效果并不需要太多的工作,因为您已经有了一个for循环来枚举所选的元素。
当链接方法对包含在jQuery对象中的元素集进行更大的改变时,您开始从 fluent API 中获得真正的好处。清单 5-23 提供了一个演示。
清单 5-23 。一个更复杂的链接示例
...
<script type="text/javascript">
$(document).ready(function() {
$("label").css("color", "blue").add("input[name!='rose']")
.filter("[for!='snowdrop']").css("font-size", ".75em");
var elems = document.getElementsByTagName("label");
for (var i = 0; i < elems.length; i++) {
elems[i].style.color = "blue";
if (elems[i].getAttribute("for") != "snowdrop") {
elems[i].style.fontSize= ".75em";
}
}
elems = document.getElementsByTagName("input");
for (var i = 0; i < elems.length; i++) {
if (elems[i].getAttribute("name") != "rose") {
elems[i].style.fontSize= ".75em";
}
}
});
</script>
...
这是一个夸张的例子,但是它展示了 jQuery 提供的灵活性。让我们分解链接的方法,以了解正在发生的事情。我从这个开始:
...
$("label").css("color", "blue")
...
我已经选择了文档中所有的label元素,并将它们的 CSS color属性的值设置为blue。下一步如下:
...
$("label").css("color", "blue").add("input[name!='rose']")
...
add方法将匹配指定选择器的元素添加到jQuery对象中。在本例中,我选择了没有值为rose的name属性的input元素。这些元素与之前匹配的元素组合在一起,给我一个包含混合了label和input元素的jQuery对象。你会在第六章的中看到更多的add方法。下面是下一个新增内容:
...
$("label").css("color", "blue").add("input[name!='rose']").filter("[for!='snowdrop']")
...
filter方法删除 jQuery 对象中不满足指定条件的所有元素。我在第六章的中更深入地解释了这个方法,但是现在知道它允许我从 jQuery 对象中移除任何具有值为snowdrop的for属性的元素就足够了。
...
$("label").css("color", "blue").add("input[name!='rose']")
.filter("[for!='snowdrop']").css("font-size", ".75em");
...
最后一步是再次调用css方法,这次将font-size属性设置为.75em。最终结果如下:
- 所有的
label元素都被赋予了colorCSS 属性的值blue。 - 除了具有
snowdrop属性值的标签元素之外,所有标签元素都被赋予 CSSfont-size属性的值.75em。 - 所有没有
rose的name属性值的input元素都被赋予 CSSfont-size属性的.75em值。
使用基本的 DOM API 实现相同的效果要复杂得多,我在编写这个脚本时遇到了一些困难。例如,我认为我可以使用第二章中描述的document.querySelectorAll方法,使用选择器input[name!='rose']选择input元素,但是结果证明这种属性过滤器不能与该方法一起工作。然后,我试图通过将两个getElementsByTagName调用的结果连接在一起来避免重复调用来设置font-size值,但是这本身就是一个痛苦的经历。我不想赘述这一点,特别是因为您必须已经对 jQuery 有了一定的了解才能阅读这本书,但是 jQuery 提供了一定程度的流畅性和表现力,这是使用基本的 DOM API 不可能实现的。
处理事件
回到我开始这一章的脚本,你可以看到我将两个方法调用链接在一起,如清单 5-24 中突出显示的。
清单 5-24 。示例脚本中的链式方法调用
...
<script type="text/javascript">
$(document).ready(function() {
$("img:odd").mouseenter(function(e) {
$(this).css("opacity", 0.5);
}).mouseout(function(e) {
$(this).css("opacity", 1.0);
})
});
</script>
...
我链接的方法是mouseenter和mouseout。这些方法让我为我在第二章的中描述的mouseenter和mouseout事件定义处理函数。我在第九章中介绍了 jQuery 对事件的支持,但我只是想展示如何使用jQuery对象的行为来为你选择的所有元素指定一个单独的处理方法。
摘要
在本章中,我向您介绍了您的第一个 jQuery 脚本,并使用它来演示 jQuery 库的一些关键特性:$函数、ready事件、jQuery结果对象,以及 jQuery 如何补充而不是取代作为 HTML 规范一部分的内置 DOM API。
六、管理元素选择
大多数时候,jQuery 的使用遵循一个独特的两步模式。第一步是选择一些元素,第二步是对这些元素执行一个或多个操作。在这一章中,我将重点介绍第一步,向您展示如何控制 jQuery 选择,并根据您的具体需求对其进行裁剪。我还将向您展示如何使用 jQuery 导航 DOM。在这两种情况下,您都从一个选择开始并对其执行操作,直到它只包含您需要的元素。正如您将看到的,开始时的元素和结束时的元素之间的关联可以简单,也可以复杂。表 6-1 对本章进行了总结。
表 6-1 。章节总结
| 问题 | 解决办法 | 列表 |
|---|---|---|
| 展开选择。 | 使用add方法。 | one |
| 将选择范围缩小到单个元素。 | 使用first、last或eq方法。 | Two |
| 将选择范围缩小到一系列元素。 | 使用slice方法。 | three |
| 通过应用过滤器减少选择。 | 使用filter或not方法。 | 4, 5 |
| 根据选定元素的后代缩小选择范围。 | 使用has方法。 | six |
| 从现有选择中投影新选择。 | 使用map方法。 | seven |
| 检查是否至少有一个选定元素满足特定条件。 | 使用is方法。 | eight |
| 恢复到以前的选择。 | 使用end方法。 | nine |
| 将上一个选择添加到当前选择。 | 使用addBack方法。 | Ten |
| 导航到选定元素的子代和后代。 | 使用children和find方法。 | 11–13 |
| 导航到所选元素的父元素。 | 使用parent方法。 | Fourteen |
| 导航到祖先或选定的元素。 | 使用parents方法。 | Fifteen |
| 导航到元素的祖先,直到遇到特定的元素。 | 使用parentsUntil方法。 | 16, 17 |
| 导航到与选择器匹配或者是特定元素的最近祖先。 | 使用closest方法。 | 18, 19 |
| 导航到最近的定位祖先。 | 使用offsetParent方法。 | Twenty |
| 导航到所选元素的同级元素。 | 使用siblings方法。 | 21, 22 |
| 导航到所选元素的上一个或下一个同级元素。 | 使用下一个、prev、nextAll、prevAll、nextUntil或prevUntil方法。 | Twenty-three |
自上一版以来,JQUERY 发生了变化
在 jQuery 1.9 中,addBack方法已经用addBack方法取代了 jQuery 1.8 的addSelf方法。这些方法执行相同的功能,这将在本章的“更改然后展开选择”一节中演示。
扩展选择
add方法允许您通过添加额外的元素来扩展jQuery对象的内容。表 6-2 显示了你可以使用的不同参数。
表 6-2 。添加方法参数类型
| 争论 | 描述 |
|---|---|
add(selector) add(selector, context) | 添加选择器匹配的所有元素,无论有无上下文。 |
add(HTMLElement) add(HTMLElement[]) | 添加单个HTMLElement或一组HTMLElement对象。 |
add(jQuery) | 添加指定jQuery对象的内容。 |
像许多 jQuery 方法一样,add方法返回一个jQuery对象,在这个对象上可以调用其他方法,包括对add方法的进一步调用。清单 6-1 展示了使用add方法来扩展一组元素。
清单 6-1 。使用 add 方法
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<script src="jquery-2.0.2.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="styles.css"/>
<script type="text/javascript">
$(document).ready(function () {
var labelElems = document.getElementsByTagName("label");
var jq = $("img[src*=daffodil]");
$("img:even").add("img[src*=primula]").add(jq)
.add(labelElems).css("border", "thick double red");
});
</script>
</head>
<body>
<h1>Jacqui's Flower Shop</h1>
<form method="post">
<div id="oblock">
<div class="dtable">
<div id="row1" class="drow">
<div class="dcell">
<img src="aster.png"/><label for="aster">Aster:</label>
<input name="aster" value="0" required>
</div>
<div class="dcell">
<img src="daffodil.png"/><label for="daffodil">Daffodil:</label>
<input name="daffodil" value="0" required >
</div>
<div class="dcell">
<img src="rose.png"/><label for="rose">Rose:</label>
<input name="rose" value="0" required>
</div>
</div>
<div id="row2"class="drow">
<div class="dcell">
<img src="peony.png"/><label for="peony">Peony:</label>
<input name="peony" value="0" required>
</div>
<div class="dcell">
<img src="primula.png"/><label for="primula">Primula:</label>
<input name="primula" value="0" required>
</div>
<div class="dcell">
<img src="snowdrop.png"/><label for="snowdrop">Snowdrop:</label>
<input name="snowdrop" value="0" required>
</div>
</div>
</div>
</div>
<div id="buttonDiv"><button type="submit">Place Order</button></div>
</form>
</body>
</html>
注意一个常见的错误是假设
remove方法是add方法的对应方法,这会缩小选择范围。事实上,remove方法改变了 DOM 的结构,正如我在第七章中解释的那样。请使用我在“缩小选择范围”一节中描述的方法之一。
本例中的脚本使用所有三种方法向初始选择添加元素:使用另一个选择器、一些HTMLElement对象和另一个jQuery对象。一旦我建立了我的对象集,我就调用css方法来为border属性设置一个值,其效果是在选中的元素周围画一个红色的粗边框,如图图 6-1 所示。
图 6-1 。使用 add 方法扩展选定内容
缩小选择范围
有很多方法可以让你从选择中移除元素,如表 6-3 所述。在每种情况下,这些方法都返回一个新的jQuery对象,该对象包含减少的元素选择 。调用该方法的jQuery对象保持不变。
表 6-3 。过滤元素的方法
| 方法 | 描述 |
|---|---|
eq(index) | 移除除指定索引处的元素之外的所有元素。 |
filter(condition) | 移除不符合指定条件的元素。请参阅后面的讨论,了解可以在此方法中使用的参数的详细信息。 |
first() | 移除除第一个元素之外的所有元素。 |
has(selector)``has(jQuery)``has(HTMLElement) | 删除没有与指定选择器或jQuery对象匹配的后代的元素,或者其后代不包含指定HTMLElement对象的元素。 |
last() | 移除除最后一个元素之外的所有元素。 |
not(condition) | 移除所有符合条件的元素。有关如何指定条件的详细信息,请参见后面的讨论。 |
slice(start, end) | 移除指定索引值范围之外的所有元素。 |
将选择缩小到特定元素
三种最基本的缩小方法是first、last和eq。这三种方法允许您根据其在jQuery对象中的位置选择特定的元素。清单 6-2 提供了一个演示。
清单 6-2 。根据元素位置减少选择
...
<script type="text/javascript">
$(document).ready(function() {
var jq = $("label");
jq.first().css("border", "thick double red");
jq.last().css("border", "thick double green");
jq.eq(2).css("border", "thick double black");
jq.eq(-2).css("border", "thick double black");
});
</script>
...
注意,我调用了两次eq方法。当该方法的参数为正时,索引从jQuery对象中的第一个元素开始计数。当参数为负时,从最后一个元素开始向后计数。你可以在图 6-2 中看到这个脚本的效果。
图 6-2 。将选择范围缩小到特定元素
按范围缩小选择范围
slice方法将选择缩小到一系列元素,如清单 6-3 所示。
清单 6-3 。使用切片方法
...
<script type="text/javascript">
$(document).ready(function() {
var jq = $("label");
jq.slice(0, 2).css("border", "thick double black");
jq.slice(4).css("border", "thick solid red");
});
</script>
...
slice方法的参数是开始选择的索引和结束选择的索引。索引是从零开始的,所以我在示例中使用的参数(0和2)选择了前两个元素。如果省略第二个参数,则选择继续到元素集的末尾。通过为一组六个元素指定一个参数4,我选择了最后两个元素(它们的索引值为4和5)。你可以在图 6-3 中看到这个脚本的结果。
图 6-3 。按范围缩小选择范围
过滤元件
filter方法从选择中删除不满足指定条件的元素。表 6-4 显示了可用于表示过滤条件的不同参数。
表 6-4 。筛选方法参数类型
| 争论 | 描述 |
|---|---|
filter(selector) | 移除与选择器不匹配的元素。 |
filter(HTMLElement) | 移除指定元素以外的所有元素。 |
filter(jQuery) | 删除不包含在指定的jQuery对象中的元素。 |
filter(function(index)) | 为每个元素调用该函数;函数返回false的那些被删除。 |
清单 6-4 展示了指定过滤器的所有四种方式。
清单 6-4 。指定过滤器
...
<script type="text/javascript">
$(document).ready(function() {
$("img").filter("[src*=s]").css("border", "thick double red");
var jq = $("[for*=p]" );
$("label").filter(jq).css("color", "blue");
var elem = document.getElementsByTagName("label")[1];
$("label").filter(elem).css("font-size", "1.5em");
$("img").filter(function(index) {
return this.getAttribute("src") == "peony.png" || index == 4;
}).css("border", "thick solid red")
});
</script>
...
前三种技术是不言而喻的:您可以基于选择器、另一个jQuery对象或一个HTMLElement对象进行过滤。
第四种技术依赖于一个function,需要更多的解释。jQuery 为jQuery对象包含的每个元素调用一次该函数。如果函数返回true,那么元素被保留,如果函数返回false,它被移除。
有一个参数传递给该函数,它是调用该函数的元素的索引。另外,将this变量设置为需要处理的 HTMLElement对象。在清单中,如果元素的 src属性和特定的索引值有特定的值,我将返回true。你可以在图 6-4 中看到结果。
图 6-4 。使用过滤方法
提示你可能想知道为什么我在过滤函数中对
HTMLElement使用了getAttribute方法,而不是调用src属性。原因是getAttribute方法将返回我为文档中的src 属性设置的值(这是一个相对 URL),但是src 属性将返回一个完全限定的 URL。对于这个例子,相对 URL 更容易处理。
对filter方法的补充是not,它的工作方式基本相同,但过滤过程相反。表 6-5 显示了使用not方法应用条件的不同方式。
表 6-5 。非方法参数类型
| 争论 | 描述 |
|---|---|
not(selector) | 移除与选择器匹配的元素。 |
not(HTMLElement[]) not(HTMLElement) | 移除一个或多个指定元素。 |
not(jQuery) | 移除包含在指定jQuery对象中的元素。 |
not(function(index)) | 为每个元素调用该函数;函数返回true的那些被删除。 |
基于前面的例子,清单 6-5 展示了not方法的使用。
清单 6-5 。使用 not 方法
...
<script type="text/javascript">
$(document).ready(function() {
$("img").not("[src*=s]").css("border", "thick double red");
var jq = $("[for*=p]");
$("label").not(jq).css("color", "blue");
var elem = document.getElementsByTagName("label")[1];
$("label").not(elem).css("font-size", "1.5em");
$("img").not(function(index) {
return this.getAttribute("src") == "peony.png" || index == 4;
}).css("border", "thick solid red")
});
</script>
...
你可以在图 6-5 中看到这个脚本的效果。当然,这与前一个例子的效果相反。
图 6-5 。使用 not 方法过滤元素
减少基于后代的选择
has方法将选择减少到具有特定后代的元素,通过选择器或一个或多个HTMLElement对象指定,如清单 6-6 所示。
清单 6-6 。使用散列方法
...
<script type="text/javascript">
$(document).ready(function() {
$("div.dcell").has("img[src*=aster]").css("border", "thick solid red");
var jq = $("[for*=p]");
$("div.dcell").has(jq).css("border", "thick solid blue");
});
</script>
...
在第一种情况下,我使用了一个选择器,将选择范围缩小到至少有一个后代元素img的元素,其src属性值包含aster。在第二种情况下,我使用了一个jQuery对象,我将选择范围缩小到至少有一个后代的元素,这个后代的for属性的值包含字母p。你可以在图 6-6 中看到这个脚本的效果。
图 6-6 。使用 has 方法减少选择
映射选择
map方法提供了一种灵活的方式来使用一个jQuery对象作为基于函数创建另一个对象的手段。源jQuery对象中的每个元素都调用该函数,函数返回的HTMLElement对象包含在结果jQuery对象中,如清单 6-7 所示。
清单 6-7 。使用地图方法
...
<script type="text/javascript">
$(document).ready(function() {
$("div.dcell").map(function(index, elem) {
return elem.getElementsByTagName("img")[0];
}).css("border", "thick solid red");
$("div.dcell").map(function(index, elem) {
return $(elem).children()[1];
}).css("border", "thick solid blue");
});
</script>
...
在这个脚本中,我执行了两个映射操作。第一个使用 DOM API 返回每个元素中包含的第一个img元素,第二个使用 jQuery 返回 children 方法返回的jQuery对象中的第一个项目(我将在本章后面详细解释这个方法,但是顾名思义,它返回一个jQuery对象中每个元素的子节点)。你可以在图 6-7 的中看到结果。
图 6-7 。使用地图方法
提示每次调用函数只能返回一个元素。如果您想要为每个源元素投影多个结果元素,您可以组合使用
each和add方法,我在第八章的中对此进行了描述。
测试选择
is方法确定jQuery对象中的一个或多个元素是否满足特定条件。表 6-6 显示了你可以传递给is方法的参数。
表 6-6 。是方法参数类型
| 争论 | 描述 |
|---|---|
is(selector) | 如果jQuery对象包含选择器匹配的至少一个元素,则返回true。 |
is(HTMLElement[]) is(HTMLElement) | 如果jQuery对象包含指定的元素,或者指定数组中的至少一个元素,则返回true。 |
is(jQuery) | 如果jQuery对象包含 argument 对象中的至少一个元素,则返回true。 |
is(function(index)) | 如果函数至少返回true一次,则返回true。 |
当您指定一个函数作为条件时,jQuery 将为jQuery对象中的每个元素调用一次该函数,将元素的索引作为函数参数传递,并将this变量设置为元素本身。清单 6-8 显示了正在使用的is方法。
注意这个方法返回一个布尔值。正如我在《??》第五章中提到的,并不是所有的 jQuery 方法都返回一个
jQuery对象。
清单 6-8 。使用 is 方法
...
<script type="text/javascript">
$(document).ready(function() {
var isResult = $("img").is(function(index){
return this.getAttribute("src") == "rose.png";
});
console.log("Result: " + isResult);
});
</script>
...
该脚本测试jQuery对象是否包含一个其src属性值为rose.png的元素,并将结果写到控制台,如下所示:
Result: true
更改然后展开选择
当您通过将方法链接在一起来修改选择时,jQuery 会保留一个历史堆栈,您可以使用几个方法来利用这一点,如表 6-7 中所述。
表 6-7 。展开选择堆栈的方法
| 方法 | 描述 |
|---|---|
end() | 从堆栈中弹出当前选择并返回到上一个选择。 |
addBack() addBack(selector) | 将上一个选择添加到当前选择,并使用可选选择器过滤上一个选择。 |
end方法返回到之前的选择,这允许你选择一些元素,扩大或缩小选择,执行一些操作,然后返回到最初的选择,如清单 6-9 所示。
清单 6-9 。使用结束方法
...
<script type="text/javascript">
$(document).ready(function() {
$("label").first().css("border", "thick solid blue")
.end().css("font-size", "1.5em");
});
</script>
...
在这个脚本中,我首先选择文档中所有的 label元素。然后,我通过调用first方法缩小选择范围(以获得第一个匹配的元素),然后使用css方法为 CSS border属性设置一个值,其效果是只更改第一个选择的元素的 CSS 属性。
然后,我调用end方法返回到之前的选择(这将把选择的第一个label元素移回到label元素的所有)。然后我再次调用css方法,这一次为font-size属性设置一个值。这个 CSS 属性应用于所有的label元素,如图图 6-8 所示。
图 6-8 。使用结束方法
addBack方法将堆栈中上一个选择的内容添加到当前选择中。清单 6-10 显示了正在使用的addBack方法。
清单 6-10 。使用 andSelf 方法
...
<script type="text/javascript">
$(document).ready(function() {
$("div.dcell").children("img").addBack().css("border", "thick solid blue");
});
</script>
...
注jQuery 1.9/2.0 中的
addBack方法取代了andSelf方法。新方法执行相同的功能,并支持一个附加的选择器参数来过滤选择。
在这个例子中,我选择了所有属于dcell类成员的 div元素,然后使用 children 方法选择所有属于它们的子元素的img元素(我将在本章后面的导航 DOM 一节中详细解释children方法)。然后我调用addBack方法,该方法在一个jQuery对象中将之前的选择(div元素)与当前的选择(img元素)结合起来。最后,我调用使用css方法为选中的元素设置边框。你可以在图 6-9 中看到这个脚本的效果。
图 6-9 。使用回加方法
在 DOM 中导航
您可以使用一个选择作为在 DOM 中导航的起点,使用一个选择作为创建另一个选择的起点。在接下来的小节中,我将描述和演示 jQuery 导航方法。在本节中,我提到了我在第二章中介绍的元素之间可能存在的不同类型的关系。
提示下面几节描述的所有方法都返回一个
jQuery对象。如果有匹配的元素,这个对象将包含它们,如果没有匹配的元素,这个对象将为空(也就是说,length属性将为零)。
向下导航到层次结构
当您向下导航 DOM 层次结构时,您选择的是包含在一个jQuery对象中的元素的子元素和子元素。表 6-8 描述了相关的 jQuery 方法。
表 6-8 。方法在 DOM 层次结构中向下导航
| 方法 | 描述 |
|---|---|
children() | 选择jQuery对象中所有元素的子元素。 |
children(selector) | 选择所有与选择器匹配的元素,这些元素是jQuery对象中元素的子元素。 |
contents() | 返回jQuery对象中所有元素的子元素和文本内容。 |
find() | 选择jQuery对象中元素的后代。 |
find(selector) | 选择与选择器匹配的元素,这些元素是jQuery对象中元素的后代。 |
find(jQuery)``find(HTMLElement) | 选择jQuery对象和 argument 对象中元素的子元素之间的交集。 |
children方法将只选择那些是jQuery对象中每个元素的直接后代的元素,可选地由选择器过滤。find方法将选择所有的后代元素,而不仅仅是直接的。contents方法将返回子元素,以及任何文本内容。清单 6-11 显示了正在使用的children和find方法。
清单 6-11 。使用子代和查找方法
...
<script type="text/javascript">
$(document).ready(function() {
var childCount = $("div.drow").children().each(function(index, elem) {
console.log("Child: " + elem.tagName + " " + elem.className);
}).length;
console.log("There are " + childCount + " children");
var descCount = $("div.drow").find("img").each(function(index, elem) {
console.log("Descendant: " + elem.tagName + " " + elem.src);
}).length;
console.log("There are " + descCount + " img descendants");
});
</script>
...
在这个例子中,我使用不带选择器的children方法和带选择器的find方法。我将所选元素的详细信息以及选择了多少元素写入控制台。该脚本的控制台输出如下:
Child: DIV dcell
Child: DIV dcell
Child: DIV dcell
Child: DIV dcell
Child: DIV dcell
Child: DIV dcell
There are 6 children
Descendant: IMGhttp://www.jacquisflowershop.com/jquery/aster.png
Descendant: IMGhttp://www.jacquisflowershop.com/jquery/daffodil.png
Descendant: IMGhttp://www.jacquisflowershop.com/jquery/rose.png
Descendant: IMGhttp://www.jacquisflowershop.com/jquery/peony.png
Descendant: IMGhttp://www.jacquisflowershop.com/jquery/primula.png
Descendant: IMGhttp://www.jacquisflowershop.com/jquery/snowdrop.png
There are 6 img descendants
children和find方法的一个很好的特性是在选择中不会收到重复的元素。清单 6-12 提供了一个演示。
清单 6-12 。生成具有重叠后代的选择
...
<script type="text/javascript">
$(document).ready(function() {
$("div.drow").add("div.dcell").find("img").each(function(index, elem) {
console.log("Element: " + elem.tagName + " " + elem.src);
});
});
</script>
...
在这个例子中,我首先创建一个包含所有属于drow类的div元素和所有属于dcell类的div元素的jQuery对象。请注意,dcell类的所有成员都包含在drow类的成员中,这意味着当我使用带有img选择器的find方法时,您会有重叠的后代集和潜在的重复,因为img元素是两个div元素类的后代。但是 jQuery 确保返回的元素中没有重复的元素,如清单生成的控制台输出所示:
Element: IMGhttp://www.jacquisflowershop.com/jquery/aster.png
Element: IMGhttp://www.jacquisflowershop.com/jquery/daffodil.png
Element: IMGhttp://www.jacquisflowershop.com/jquery/rose.png
Element: IMGhttp://www.jacquisflowershop.com/jquery/peony.png
Element: IMGhttp://www.jacquisflowershop.com/jquery/primula.png
Element: IMGhttp://www.jacquisflowershop.com/jquery/snowdrop.png
使用 find 方法创建交集
你可以将一个jQuery对象、一个HTMLElement对象或者一组HTMLElement对象作为参数传递给find方法。当你这样做时,你选择了源jQuery对象的后代和参数对象的元素之间的交集。清单 6-13 提供了一个演示。
清单 6-13 。使用 find 方法创建交集
...
<script type="text/javascript">
$(document).ready(function() {
var jq = $("label").filter("[for*=p]").not("[for=peony]");
$("div.drow").find(jq).css("border", "thick solid blue");
});
</script>
...
正如这个脚本所演示的,这种方法的优点是您可以指定与后代相交的元素。我创建了一个jQuery对象,然后使用filter和not方法对其进行缩减。然后,这个对象成为另一个包含drow类中所有div元素的jQuery对象上的find方法的参数。最后的选择是div.drow元素的后代和我的label元素精简集之间的交集。你可以在图 6-10 中看到脚本的效果。
图 6-10 。使用 find 方法创建交集
在层级中向上导航
当您在 DOM 层次结构中导航时,您会对包含在一个jQuery对象中的元素的父元素和祖先元素感兴趣。表 6-9 显示了你可以用来向上导航的方法。
表 6-9 。在 DOM 层次结构中向上导航的方法
| 方法 | 描述 |
|---|---|
closest(selector) closest(selector, context) | 为与指定选择器相交的jQuery对象中的每个元素选择最近的祖先。 |
closest(jQuery) closest(HTMLElement) | 为与 argument 对象中包含的元素相交的jQuery对象中的每个元素选择最近的祖先。 |
offsetParent() | 查找 CSS 位置属性值为fixed、absolute或relative的最近的祖先。 |
parent() parent(selector) | 选择jQuery对象中每个元素的父元素,可选地由选择器过滤。 |
parents() parents(selector) | 选择jQuery对象中每个元素的祖先,可选地由选择器过滤。 |
parentsUntil(selector) parentsUntil(selector, selector) | 选择jQuery对象中每个元素的祖先,直到遇到匹配的选择器。可以使用第二个选择器过滤结果。 |
parentsUntil(HTMLElement)``parentsUntil(HTMLElement, selector)``parentsUntil(HTMLElement[]) | 选择jQuery对象中每个元素的祖先,直到遇到一个指定的元素。可以使用选择器过滤结果。 |
选择父元素
parent方法为jQuery对象中的每个元素选择父元素。如果您提供了一个选择器,那么只有匹配该选择器的父元素才会包含在结果中。清单 6-14 显示了使用中的父元素。
清单 6-14 。使用父元素
...
<script type="text/javascript">
$(document).ready(function() {
$("div.dcell").parent().each(function(index, elem) {
console.log("Element: " + elem.tagName + " " + elem.id);
});
$("div.dcell").parent("#row1").each(function(index, elem) {
console.log("Filtered Element: " + elem.tagName + " " + elem.id);
});
});
</script>
...
在这个脚本中,我选择了所有属于dcell类的div元素,并调用parent方法来选择父元素。我还演示了如何使用带有选择器的parent方法。我使用each方法将关于所选父元素的信息写入控制台,控制台产生以下输出:
Element: DIV row1
Element: DIV row2
Filtered Element: DIV row1
选择祖先
parents方法(注意最后一个字母s)选择jQuery对象中元素的所有祖先,而不仅仅是直接的父元素。同样,您可以将选择器作为方法传递给参数来过滤结果。清单 6-15 演示了parents方法。
清单 6-15 。使用双亲方法
...
<script type="text/javascript">
$(document).ready(function() {
$("img[src*=peony], img[src*=rose]").parents().each(function(index, elem) {
console.log("Element: " + elem.tagName + " " + elem.className + " "
+ elem.id);
});
});
</script>
...
在这个例子中,我选择了两个img元素,并使用了parents方法来选择它们的祖先。然后,我将每个祖先的信息写入控制台,产生以下输出:
Element: DIV dcell
Element: DIV drow row2
Element: DIV dcell
Element: DIV drow row1
Element: DIV dtable
Element: DIV oblock
Element: FORM
Element: BODY
Element: HTML
选择祖先的一个变体由parentsUntil方法表示。对于jQuery对象中的每个元素,parentsUntil方法在 DOM 层次结构中一路向上,选择祖先元素,直到遇到匹配选择器的元素。清单 6-16 提供了一个演示。
清单 6-16 。使用 parentsUntil 方法
...
<script>
$(document).ready(function() {
$("img[src*=peony], img[src*=rose]").parentsUntil("form")
.each(function(index, elem) {
console.log("Element: " + elem.tagName + " " + elem.className
+ " " + elem.id);
});
});
</script>
...
在这个例子中,选择每个元素的祖先,直到遇到一个form元素。该脚本的输出如下:
Element: DIV dcell
Element: DIV drow row2
Element: DIV dcell
Element: DIV drow row1
Element: DIV dtable
Element: DIV oblock
请注意,匹配选择器的元素被排除在所选祖先之外。在本例中,这意味着表单元素被排除。您可以通过提供第二个选择器参数来过滤祖先集,如清单 6-17 所示。
清单 6-17 。筛选由 parentsUntil 方法选择的元素集
...
<script type="text/javascript">
$(document).ready(function() {
$("img[src*=peony], img[src*=rose]").parentsUntil("form", ":not(.dcell)")
.each(function(index, elem) {
console.log("Element: " + elem.tagName + " " + elem.className
+ " " + elem.id);
});
});
</script>
...
在这个例子中,我添加了一个选择器,它将过滤掉属于dcell类的元素。该脚本的输出如下:
Element: DIV drow row2
Element: DIV drow row1
Element: DIV dtable
Element: DIV oblock
选择第一个匹配的祖先
closest方法为jQuery对象中的每个元素选择一个选择器匹配的第一个祖先。清单 6-18 提供了一个演示。
清单 6-18 。使用最接近的方法
...
<script type="text/javascript">
$(document).ready(function() {
$("img").closest(".drow").each(function(index, elem) {
console.log("Element: " + elem.tagName + " " + elem.className
+ " " + elem.id);
});
var contextElem = document.getElementById("row1");
$("img").closest(".drow", contextElem).each(function(index, elem) {
console.log("Context Element: " + elem.tagName + " " + elem.className
+ " " + elem.id);
});
});
</script>
...
在这个例子中,我选择文档中的img元素,然后使用closest方法找到属于drow类的最近的祖先。您可以通过指定一个HTMLElement对象作为该方法的第二个参数来缩小选择祖先的范围。不是上下文对象或者不是上下文对象后代的祖先被排除在选择之外。该脚本的输出如下:
Element: DIV drow row1
Element: DIV drow row2
Context Element: DIV drow row2
当您指定一个jQuery对象或一个或多个HTMLElement对象作为closest方法的参数时,jQuery 会沿着源jQuery对象中每个元素的层次结构向上搜索,匹配它找到的第一个参数对象。清单 6-19 中的展示了这一点。
清单 6-19 。使用一组参考对象的最近方法
...
<script type="text/javascript">
$(document).ready(function() {
var jq = $("#row1, #row2, form");
$("img[src*=rose]").closest(jq).each(function(index, elem) {
console.log("Context Element: " + elem.tagName + " " + elem.className
+ " " + elem.id);
});
});
</script>
...
在这个例子中,我选择文档中的一个img元素,然后使用closest方法选择祖先元素。我提供了一个包含form元素和带有row1和row2 ID 的元素的jQuery对象作为closest方法的参数。jQuery 将选择与img元素最接近的元素。换句话说,它将开始在层次结构中向上移动,直到遇到 argument 对象中的一个元素。该脚本的输出如下:
Context Element: DIV drow row1
offsetParent是最近的主题的变体,并且资助第一个祖先,该祖先具有relative、absolute或fixed的position CSS 属性的值。这样的元素被称为定位祖先,在处理动画时找到一个元素会很有用(关于 jQuery 对动画支持的详细信息,请参见第十章)。清单 6-20 包含了这种方法的演示。
清单 6-20 。使用 offsetParent 方法
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<script src="jquery-2.0.2.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="styles.css"/>
<style type="text/css">
#oblock {position: fixed; top: 120px; left: 50px}
</style>
<script type="text/javascript">
$(document).ready(function() {
$("img[src*=aster]").offsetParent().css("background-color", "lightgrey");
});
</script>
</head>
<body>
<h1>Jacqui's Flower Shop</h1>
<form method="post">
<div id="oblock">
<div class="dtable">
<div id="row1" class="drow">
<div class="dcell">
<img src="aster.png"/><label for="aster">Aster:</label>
<input name="aster" value="0" required>
</div>
<div class="dcell">
<img src="daffodil.png"/><label for="daffodil">Daffodil:</label>
<input name="daffodil" value="0" required >
</div>
<div class="dcell">
<img src="rose.png"/><label for="rose">Rose:</label>
<input name="rose" value="0" required>
</div>
</div>
</div>
</div>
<div id="buttonDiv"><button type="submit">Place Order</button></div>
</form>
</body>
</html>
在这个示例文档的简化版本中,我使用 CSS 为具有oblock的id的元素的position属性设置了一个值。在脚本中,我使用 jQuery 来选择一个img元素,然后调用offsetParent方法来查找位置最近的元素。该方法在层次结构中一直向上,直到到达具有所需值之一的元素。我使用css属性为所选元素的background-color属性设置一个值,如图 6-11 中的所示。
图 6-11 。寻找位置最近的祖先
在层次结构中导航
DOM 导航的最终形式处理兄弟节点。jQuery 为此提供的方法在表 6-10 中描述。
表 6-10 。方法在 DOM 层次结构中导航
| 方法 | 描述 |
|---|---|
next() next(selector) | 为jQuery对象中的每个元素选择紧邻的下一个兄弟元素,可选地由选择器过滤。 |
nextAll() nextAll(selector) | 为jQuery对象中的每个元素选择所有下一个兄弟元素,可选地由选择器过滤。 |
nextUntil((selector) nextUntil(selector, selector) nextUntil(jQuery) nextUntil(jQuery, selector) nextUntil(HTMLElement[]) | 为每个元素选择下一个兄弟元素,直到(不包括)与选择器匹配的元素或jQuery对象或HTMLElement数组中的元素。结果可以选择性地由选择器筛选,作为方法的第二个参数。 |
prev() prev(selector) | 为jQuery对象中的每个元素选择上一个同级元素,可选地由选择器过滤。 |
prevAll() prevAll(selector) | 为jQuery对象中的每个元素选择所有以前的兄弟元素,可选地由选择器过滤。 |
prevUntil(selector) prevUntil(selector, selector) prevUntil(jQuery) prevUntil(jQuery, selector) prevUntil(HTMLElement[]) | 选择每个元素的前一个兄弟元素,直到(不包括)与选择器匹配的元素或jQuery对象或HTMLElement数组中的元素。结果可以选择性地由选择器筛选,作为方法的第二个参数。 |
siblings() siblings(selector) | 为jQuery对象中的每个元素选择所有同级元素,可选地由选择器过滤。 |
选择所有兄弟姐妹
siblings方法选择一个jQuery对象中所有元素的所有兄弟元素。清单 6-21 展示了这种方法的使用。(对于这个清单,我已经返回了完整的花店文档)。
清单 6-21 。使用兄弟姐妹方法
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<script src="jquery-2.0.2.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="styles.css"/>
<script type="text/javascript">
$(document).ready(function () {
$("img[src*=aster], img[src*=primula]")
.parent().siblings().css("border", "thick solid blue");
});
</script>
</head>
<body>
<h1>Jacqui's Flower Shop</h1>
<form method="post">
<div id="oblock">
<div class="dtable">
<div id="row1" class="drow">
<div class="dcell">
<img src="aster.png"/><label for="aster">Aster:</label>
<input name="aster" value="0" required>
</div>
<div class="dcell">
<img src="daffodil.png"/><label for="daffodil">Daffodil:</label>
<input name="daffodil" value="0" required >
</div>
<div class="dcell">
<img src="rose.png"/><label for="rose">Rose:</label>
<input name="rose" value="0" required>
</div>
</div>
<div id="row2"class="drow">
<div class="dcell">
<img src="peony.png"/><label for="peony">Peony:</label>
<input name="peony" value="0" required>
</div>
<div class="dcell">
<img src="primula.png"/><label for="primula">Primula:</label>
<input name="primula" value="0" required>
</div>
<div class="dcell">
<img src="snowdrop.png"/><label for="snowdrop">Snowdrop:</label>
<input name="snowdrop" value="0" required>
</div>
</div>
</div>
</div>
<div id="buttonDiv"><button type="submit">Place Order</button></div>
</form>
</body>
</html>
在这个例子中,我选择了两个img元素,调用parent方法选择它们的父元素,然后调用siblings方法选择它们的兄弟元素。前一个和下一个兄弟都将被选中,我使用css方法为border属性设置一个值。在图 6-12 中可以看到效果。(我用了parent的方法让 CSS 属性的效果更清晰。)
图 6-12 。选择同级元素
请注意,只选择了同级元素,而不是元素本身。当然,如果jQuery对象中的一个元素是另一个元素的兄弟元素,这种情况就会改变,如清单 6-22 所示。
清单 6-22 。重叠的兄弟集合
...
<script type="text/javascript">
$(document).ready(function() {
$("#row1 div.dcell").siblings().css("border", "thick solid blue");
});
</script>
...
在这个脚本中,我首先选择作为row1元素的子元素的所有div元素,然后调用siblings方法。选择中的每个元素都是至少一个其他元素的兄弟,正如你在图 6-13 中看到的。
图 6-13 。重叠的同级元素
选择下一个和上一个兄弟
我不打算演示选择下一个和上一个兄弟的所有方法,因为它们的工作方式与其他导航方法相同。清单 6-23 显示了正在使用的nextAll和prevAll方法。
清单 6-23 。使用 nextAll 和 prevAll 方法
...
<script type="text/javascript">
$(document).ready(function() {
$("img[src*=aster]").parent().nextAll().css("border", "thick solid blue");
$("img[src*=primula]").parent().prevAll().css("border", "thick double red");
});
</script>
...
该脚本为 aster 图像的父代选择下一个兄弟,为 primula 图像选择前一个兄弟。你可以在图 6-14 中看到这个脚本的效果。
图 6-14 。选择下一个和上一个同级
摘要
在这一章中,我向您展示了如何控制 jQuery 选择并根据您的具体需求对其进行裁剪,包括添加元素、过滤元素、使用映射以及测试选择以评估条件。我还向您展示了如何使用 jQuery 选择作为导航 DOM 的起点,使用一个选择作为遍历文档以创建另一个选择的起点。在第七章中,我将向您展示如何使用选择来操作 DOM,应用 jQuery 方法来创建、移除、更改和创建 HTML 元素。
七、操纵 DOM
在前一章中,我向您展示了如何选择元素。您可以对选择做的最强大的事情之一是改变 HTML 文档本身的结构,这被称为操纵 DOM 。在这一章中,我将向你展示改变结构的不同方法,包括插入元素作为其他元素的子元素、父元素或兄弟元素。我还将向您展示如何创建新元素,如何将元素从文档的一部分移动到另一部分,以及如何完全删除元素。表 7-1 对本章进行了总结。
表 7-1 。章节总结
| 问题 | 解决办法 | 列表 |
|---|---|---|
| 创造新元素。 | 通过使用clone方法或使用 DOM API,将一个 HTML 片段传递给$函数。 | 1–3 |
| 将元素作为最后一个子元素插入。 | 使用append方法。 | four |
| 将元素作为第一个子元素插入。 | 使用prepend方法。 | 5, 6 |
| 在不同的位置插入相同的元素。 | 在插入元素之前克隆它们。 | 7, 8 |
插入一个jQuery对象的内容作为其他元素的子元素。 | 使用appendTo或prependTo方法。 | nine |
| 动态插入子元素。 | 将函数传递给append或prepend方法。 | Ten |
| 插入父元素。 | 使用wrap方法。 | Eleven |
| 向多个元素插入一个公共父元素。 | 使用wrapAll方法。 | 12, 13 |
| 包装元素的内容。 | 使用wrapInner方法。 | Fourteen |
| 动态包装元素。 | 将函数传递给wrap或wrapInner方法。 | Fifteen |
| 插入同级元素。 | 使用after、before、insertAfter或insertBefore方法。 | 16, 17 |
| 动态插入同级元素。 | 将函数传递给before或after方法。 | Eighteen |
| 用其他元素替换元素。 | 使用replaceWith或replaceAll方法。 | Nineteen |
| 动态替换元素。 | 将函数传递给replaceWith方法。 | Twenty |
| 从 DOM 中移除元素。 | 使用remove或detach方法。 | 21–23 |
| 移除元素的内容。 | 使用empty方法。 | Twenty-four |
| 移除元素的父元素。 | 使用unwrap方法。 | Twenty-five |
自上一版以来,JQUERY 发生了变化
对于这一章,jQuery 1.9/2.0 中最重要的变化是在解释 HTML 字符串时采用了更严格的方法。然而,1.10/2.0.1 版本撤销了这一更改,并恢复了旧的 HTML 解析方法——详情请参见 HTML 解析的更改侧栏。
对after、before、replaceWith、appendTo、insertBefore、insertAfter和replaceAll方法的方式进行了一些幕后修改,以使它们处理jQuery对象的方式与其他 DOM 操作方法一致。这些变化不会影响本章中的技术。
创建新元素
当编写 web 应用时,您经常需要创建新元素并将它们插入到 DOM 中(尽管您也可以插入现有的元素,我将在本章后面解释)。在接下来的部分中,我将向您展示创建内容的不同方法。
提示理解创建新元素并不会自动将它们添加到 DOM 中是很重要的。您需要明确地告诉 jQuery 新元素应该放在文档中的什么位置,我将在本章后面解释这一点。
使用$函数创建元素
您可以通过向$函数传递一个 HTML 片段字符串来创建新元素。jQuery 解析字符串并创建相应的 DOM 对象。清单 7-1 包含了一个例子。
清单 7-1 。使用$函数创建新元素
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<script src="jquery-2.0.2.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="styles.css"/>
<script type="text/javascript">
$(document).ready(function() {
var newElems = $("<div class='dcell'><img src='lily.png'/></div>");
newElems.each(function (index, elem) {
console.log("New element: " + elem.tagName + " " + elem.className);
});
newElems.children().each(function(index, elem) {
console.log("Child: " + elem.tagName + " " + elem.src);
});
});
</script>
</head>
<body>
<h1>Jacqui's Flower Shop</h1>
<form method="post">
<div id="oblock">
<div class="dtable">
<div id="row1" class="drow">
<div class="dcell">
<img src="aster.png"/><label for="aster">Aster:</label>
<input name="aster" value="0" required>
</div>
<div class="dcell">
<img src="daffodil.png"/><label for="daffodil">Daffodil:</label>
<input name="daffodil" value="0" required >
</div>
<div class="dcell">
<img src="rose.png"/><label for="rose">Rose:</label>
<input name="rose" value="0" required>
</div>
</div>
<div id="row2"class="drow">
<div class="dcell">
<img src="peony.png"/><label for="peony">Peony:</label>
<input name="peony" value="0" required>
</div>
<div class="dcell">
<img src="primula.png"/><label for="primula">Primula:</label>
<input name="primula" value="0" required>
</div>
<div class="dcell">
<img src="snowdrop.png"/><label for="snowdrop">Snowdrop:</label>
<input name="snowdrop" value="0" required>
</div>
</div>
</div>
</div>
<div id="buttonDiv"><button type="submit">Place Order</button></div>
</form>
</body>
</html>
在这个例子中,我从一个 HTML 片段中创建了两个新元素:一个div元素和一个img元素。因为你处理的是 HTML,所以你可以使用包含结构的片段。在这种情况下,img元素是div元素的子元素。
对 HTML 解析的更改
当您将一个字符串传递给$函数时,jQuery 必须决定它是选择器还是 HTML 字符串。在 1.9 版本之前,如果字符串中的任何地方有标签,它就被认为是 HTML(关于标签的详细信息,参见第二章)。这带来了一些罕见的问题,复杂的选择器被解释为 HTML,因此在 jQuery 1.9/2.0 中改变了策略,只有以<字符开头的字符串才被认为是 HTML。
这被证明是一个不受欢迎的改变,因此在 jQuery 1.10/2.0.1 版本中又将该策略改了回来——但是警告说在检测 HTML 字符串的方式上可能会有进一步的改变。如果您正在处理可能不明确的字符串,您可以使用parseHTML方法,它将处理一个 HTML 字符串,而没有将其解释为选择器的风险。
由$函数返回的jQuery对象只包含来自 HTML 片段的顶级元素。为了演示这一点,我使用了each函数将关于jQuery对象中每个元素的信息写入控制台。jQuery 不会丢弃子元素。它们可以通过我在第六章中描述的常用导航方法访问。为了演示这一点,我在jQuery对象上调用了children方法,并将每个子元素的信息打印到控制台。该脚本的输出如下:
New element: DIV dcell
Child: IMGhttp://www.jacquisflowershop.com/jquery/lily.png
提示您还可以提供一个 map 对象,指定应该应用于 HTML 元素的属性。你可以在第十二章中看到这个版本的
$函数。
通过克隆现有元素创建新元素
您可以使用clone方法从现有元素创建新元素。这复制了一个jQuery对象中的所有元素,以及它们的所有后代。清单 7-2 给出了一个例子。
清单 7-2 。克隆元素
...
<script type="text/javascript">
$(document).ready(function() {
var newElems = $("div.dcell").clone();
newElems.each(function (index, elem) {
console.log("New element: " + elem.tagName + " " + elem.className);
});
newElems.children("img").each(function(index, elem) {
console.log("Child: " + elem.tagName + " " + elem.src);
});
});
</script>
...
在这个脚本中,我选择并克隆了所有属于dcell类的div元素。为了演示后代元素也被克隆,我使用了带有选择器的children方法来获得克隆的img元素。我已经将div和img元素的详细信息写入控制台,产生以下输出:
New element: DIV dcell
New element: DIV dcell
New element: DIV dcell
New element: DIV dcell
New element: DIV dcell
New element: DIV dcell
Child: IMGhttp://www.jacquisflowershop.com/jquery/aster.png
Child: IMGhttp://www.jacquisflowershop.com/jquery/daffodil.png
Child: IMGhttp://www.jacquisflowershop.com/jquery/rose.png
Child: IMGhttp://www.jacquisflowershop.com/jquery/peony.png
Child: IMGhttp://www.jacquisflowershop.com/jquery/primula.png
Child: IMGhttp://www.jacquisflowershop.com/jquery/snowdrop.png
提示您可以将值
true作为参数传递给clone方法,以便在复制过程中包含事件处理程序和与元素相关的数据。省略此参数或指定值false会省略事件处理程序和数据。我将在第九章的中解释 jQuery 对事件的支持,并在第八章的中解释如何将数据与元素相关联。
使用 DOM API 创建元素
您可以直接使用 DOM API 来创建新的HTMLElement对象,当您使用其他技术时,这基本上就是 jQuery 在为您做的事情。我不打算解释 DOM API 的细节,但是清单 7-3 包含了一个简单的例子,让你知道如何使用这种技术。
清单 7-3 。使用 DOM API 创建新元素
...
<script type="text/javascript">
$(document).ready(function() {
var divElem = document.createElement("div");
divElem.classList.add("dcell");
var imgElem = document.createElement("img");
imgElem.src = "lily.png";
divElem.appendChild(imgElem);
var newElems = $(divElem);
newElems.each(function (index, elem) {
console.log("New element: " + elem.tagName + " " + elem.className);
});
newElems.children("img").each(function(index, elem) {
console.log("Child: " + elem.tagName + " " + elem.src);
});
});
</script>
...
在这个例子中,我创建并配置了一个div HTMLElement和一个img HTMLElement,并将img指定为div的子节点,就像我在第一个例子中所做的一样。以这种方式创建元素没有错,但是因为这是一本关于 jQuery 的书,所以我不想过多地讨论 DOM API 而偏离主题。
我将div HTMLElement作为参数传递给 jQuery $函数,这样我就可以使用与其他示例相同的each函数。控制台输出如下:
New element: DIV dcell
Child: IMGhttp://www.jacquisflowershop.com/jquery/lily.png
插入子元素和后代元素
一旦我创建了元素,我就可以开始将它们插入到文档中。我从查看将一个元素插入另一个元素以创建子元素和后代元素的方法开始,如表 7-2 所述。
表 7-2 。插入子元素和后代元素的方法
| 方法 | 描述 |
|---|---|
append(HTML)``append(jQuery) | 将指定元素作为 DOM 中所有元素的最后一个子元素插入。 |
prepend(HTML)``prepend(jQuery) | 将指定元素作为 DOM 中所有元素的第一个子元素插入。 |
appendTo(jQuery) appendTo(HTMLElement[]) | 将元素插入到jQuery对象中,作为参数指定的元素的最后一个子元素。 |
prependTo(HTML)``prependTo(jQuery) | 将元素插入到jQuery对象中,作为参数指定的元素的第一个子元素。 |
append(function) prepend(function) | 将一个函数的结果附加或预先添加到jQuery对象的元素中。 |
提示您还可以使用
wrapInner方法插入子元素,我在“包装元素内容”一节中对此进行了描述。此方法在元素及其现有子元素之间插入一个新的子元素。另一个技巧是使用html方法,我在第八章的中描述过。
作为参数传递给这些方法的元素被作为子元素插入到jQuery对象中的每个元素的中,这使得使用我在第六章中向您展示的技术来管理选择变得尤为重要,以便它只包含您想要使用的元素。清单 7-4 给出了使用append方法的演示。
清单 7-4 。使用 append 方法
...
<script type="text/javascript">
$(document).ready(function() {
var newElems = $("<div class='dcell'></div>")
.append("<img src='lily.png'/>")
.append("<label for='lily'>Lily:</label>")
.append("<input name='lily' value='0' required />");
newElems.css("border", "thick solid red");
$("#row1").append(newElems);
});
</script>
...
我在这个脚本中以两种不同的方式使用了append方法:首先构建我的新元素集,然后将这些元素插入 HTML 文档。由于这是我描述的第一个 DOM 操作方法,我将花点时间演示一些行为,帮助您避免最常见的与 DOM 相关的 jQuery 错误。但首先,我们来看看剧本的效果。你可以在图 7-1 的中看到添加新元素的结果。
图 7-1 。向文档中插入新元素
首先要看的是我使用append方法构建新元素的方式:
...
var newElems = $("<div class='dcell'/>").append("<img src='lily.png'/>")
.append("<label for='lily'>Lily:</label>")
.append("<input name='lily' value='0' required />");
...
我本可以创建一个包含所有元素的更大的 HTML 块,但是我想展示 DOM 操作方法的一个关键方面,即这些方法返回的jQuery对象包含与调用这些方法的对象相同的元素。
例如,我从一个包含一个div元素的jQuery对象开始,每个append方法的结果是一个包含相同div元素的jQuery对象,而不是我添加的元素。这意味着链接append调用会为最初选择的元素创建多个新的子元素。
要指出的下一个行为是,新创建的元素可能不会附加到文档中,但是您仍然可以使用 jQuery 来导航和修改它们。我想用边框突出显示新元素,所以我做了如下调用:
...
newElems.css("border", "thick solid red");
...
这是一个很好的特性,允许您创建和管理复杂的元素集,并在将它们添加到文档之前做好充分的准备。最后,我将新元素添加到文档中,如下所示:
...
$("#row1").append(newElems);
...
新元素将添加到选择的每个元素中。示例中的选择只有一个元素(带有row1中的id的元素),因此您有了添加到花店页面的新 lily 产品。
前置元素
对append方法的补充是prepend,它将新的元素作为元素的第一个子元素插入到jQuery对象中。清单 7-5 包含了一个例子。
清单 7-5 。使用前置方法
...
<script type="text/javascript">
$(document).ready(function() {
var orchidElems = $("<div class='dcell'/>")
.append("<img src='orchid.png'/>")
.append("<label for='orchid'>Orchid:</label>")
.append("<input name='orchid' value='0' required />");
var newElems = $("<div class='dcell'/>")
.append("<img src='lily.png'/>")
.append("<label for='lily'>Lily:</label>")
.append("<input name='lily' value='0' required />").add(orchidElems);
newElems.css("border", "thick solid red");
$("#row1, #row2").prepend(newElems);
});
</script>
...
除了prepend方法之外,这个脚本还演示了另一个 jQuery DOM 操作特性:作为参数传递给这些方法之一的所有元素都被添加为jQuery对象中所有元素的子元素。在这个例子中,我创建了两个div元素,一个用于百合,一个用于兰花。我使用add方法将两组元素放在一个jQuery对象中。
提示
add方法也接受包含 HTML 片段的字符串。您可以使用这个特性来替代使用jQuery对象构建新元素。
然后我创建另一个jQuery对象,它包含具有row1和row2 id值的元素,并使用prepend方法将兰花和百合元素插入到文档中。你可以在图 7-2 中看到效果。新元素以红色边框突出显示。如图所示,lily 和兰花元素已经添加到两个 row 元素中。
图 7-2 。向多个选定元素添加多个新元素
作为使用add方法的替代方法,您可以向 DOM 修改方法传递多个元素,如清单 7-6 所示。这个列表产生了与图 7-2 中所示相同的结果。
清单 7-6 。向 prepend 方法传递多个参数
...
<script type="text/javascript">
$(document).ready(function() {
var orchidElems = $("<div class='dcell'/>")
.append("<img src='orchid.png'/>")
.append("<label for='orchid'>Orchid:</label>")
.append("<input name='orchid' value='0' required />");
var lilyElems = $("<div class='dcell'/>")
.append("<img src='lily.png'/>")
.append("<label for='lily'>Lily:</label>")
.append("<input name='lily' value='0' required />");
orchidElems.css("border", "thick solid red");
lilyElems.css("border", "thick solid red");
$("#row1, #row2").prepend(lilyElems, orchidElems);
});
</script>
...
提示我使用
css方法在单独的语句中设置 CSS border属性,但这只是为了让示例更容易理解。事实上,我可以像任何其他 jQuery 方法一样链接对css方法的调用。
在不同的位置插入相同的元素
您只能向文档中添加一次新元素。此时,将它们用作 DOM 插入方法的参数会移动元素,而不是复制它们。清单 7-7 显示了这个问题。
清单 7-7 。向文档中添加新元素两次
...
<script type="text/javascript">
$(document).ready(function() {
var orchidElems = $("<div class='dcell'/>")
.append("<img src='orchid.png'/>")
.append("<label for='orchid'>Orchid:</label>")
.append("<input name='orchid' value='0' required />");
var newElems = $("<div class='dcell'/>")
.append("<img src='lily.png'/>")
.append("<label for='lily'>Lily:</label>")
.append("<input name='lily' value='0' required />").add(orchidElems);
newElems.css("border", "thick solid red");
$("#row1").append(newElems);
$("#row2").prepend(newElems);
});
</script>
...
这个脚本的意图很清楚:将新元素追加到row1中,并将它们前置到row2中。当然,这不会发生,正如图 7-3 所示。
图 7-3 。两次尝试向文档中添加新元素(但都失败了)
元素被附加到row1上,但是调用prepend的效果是移动元素,而不是添加两次。为了解决这个问题,您需要使用clone方法创建想要插入的元素的副本。清单 7-8 显示了修改后的脚本。
清单 7-8 。克隆元素,以便可以多次将它们添加到文档中
...
<script type="text/javascript">
$(document).ready(function() {
var orchidElems = $("<div class='dcell'/>")
.append("<img src='orchid.png'/>")
.append("<label for='orchid'>Orchid:</label>")
.append("<input name='orchid' value='0' required />");
var newElems = $("<div class='dcell'/>")
.append("<img src='lily.png'/>")
.append("<label for='lily'>Lily:</label>")
.append("<input name='lily' value='0' required />").add(orchidElems);
newElems.css("border", "thick solid red");
$("#row1").append(newElems);
$("#row2").prepend(newElems.clone());
});
</script>
...
现在元素被复制并插入到两个位置,如图图 7-4 所示。
图 7-4 。克隆和插入元素
从 jQuery 对象插入
您可以使用appendTo和prependTo方法来改变元素之间的关系,如清单 7-9 所示。
清单 7-9 。使用 appendTo 方法
...
<script type="text/javascript">
$(document).ready(function() {
var newElems = $("<div class='dcell'/>");
$("img").appendTo(newElems);
$("#row1").append(newElems);
});
</script>
...
我创建了jQuery对象来包含文档中的一个新的div元素和img元素。然后我使用appendTo方法添加img元素作为div元素的子元素。你可以在图 7-5 中看到结果。如您所见,该脚本的效果是将img元素移动到新的div元素,我将它附加到了row1元素上。
图 7-5 。使用 appendTo 方法
使用函数插入元素
你可以将一个function传递给append 和prepend方法。这允许您动态地为jQuery对象选择的元素插入子元素,如清单 7-10 所示。
清单 7-10 。用函数动态添加子元素
...
<script type="text/javascript">
$(document).ready(function() {
var orchidElems = $("<div class='dcell'/>")
.append("<img src='orchid.png'/>")
.append("<label for='orchid'>Orchid:</label>")
.append("<input name='orchid' value='0' required />");
var lilyElems = $("<div class='dcell'/>")
.append("<img src='lily.png'/>")
.append("<label for='lily'>Lily:</label>")
.append("<input name='lily' value='0' required />");
$(orchidElems).add(lilyElems).css("border", "thick solid red");
$("div.drow").append(function(index, html) {
if (this.id == "row1") {
return orchidElems;
} else {
return lilyElems;
}
});
});
</script>
...
该函数为jQuery对象中的每个元素调用一次。传递给函数的参数是选择中元素的索引和正在处理的元素的 HTMLHTML 是一个字符串。此外,this变量的值被设置为适当的HTMLElement。该函数的结果将被追加或前置到正在处理的元素中。你可以返回一个 HTML 片段,一个或多个HTMLElement对象,或者一个jQuery对象。
在这个例子中,我准备为 lily 和 orchid 产品创建元素集,然后根据id属性的值从append函数返回它们。你可以在图 7-6 中看到结果。
图 7-6 。基于函数动态插入元素
插入父元素和祖先元素
jQuery 为您提供了一组插入元素作为其他元素的父元素或祖先元素的方法。这被称为包装(因为一个元素被另一个元素包装)。表 7-3 描述了这些方法。
表 7-3 。包装元件的方法
| 方法 | 描述 |
|---|---|
wrap(HTML)``wrap(jQuery) | 将指定的元素环绕在jQuery对象中的每个元素周围。 |
wrapAll(HTML)``wrapAll(jQuery) | 将指定元素环绕在jQuery对象中的一组元素周围(作为一个组)。 |
wrapInner(HTML)``wrapInner(jQuery) | 将指定元素环绕在jQuery对象中元素的内容周围。 |
wrap(function) wrapInner(function) | 使用函数动态包装元素。 |
提示包装方法的补充是
unwrap,我将在本章后面的“移除元素”一节中描述它。
执行包装时,可以将多个元素作为参数传递,但必须确保只有一个内部元素。否则,jQuery 想不出该怎么办。这意味着参数中的每个元素最多只能有一个父元素和一个子元素。清单 7-11 演示了wrap方法 的使用。
清单 7-11 。使用换行方法
...
<script type="text/javascript">
$(document).ready(function() {
var newElem = $("<div/>").css("border", "thick solid red");
$("div.drow").wrap(newElem);
});
</script>
...
在这个脚本中,我创建了一个新的div元素,并使用css方法为 CSS border属性设置一个值。然后我使用wrap方法将div元素作为父元素插入到文档中的所有label元素中。在图 7-7 中可以看到效果。
图 7-7 。使用 wrap 方法向元素添加父元素
作为参数传递给wrap方法的元素被插入到jQuery对象中的每个元素和它们当前的父元素之间。举个例子,这段 HTML:
...
<div class="dtable">
<div id="row1" class="drow">
...
</div>
<div id="row2" class="drow">
...
</div>
</div>
...
是这样转化的:
...
<div class="dtable">
<div style="...style properties...">
<div id="row1" class="drow">
...
</div>
</div>
<div style="...style properties...">
<div id="row2" class="drow">
...
</div>
</div>
</div>
...
在单个父级中将元素包装在一起
当您使用wrap方法时,新元素被克隆,jQuery对象中的每个元素都有自己的新父元素。你可以使用wrapAll方法为几个元素插入一个父元素,如清单 7-12 所示。
清单 7-12 。使用 wrapAll 方法
...
<script type="text/javascript">
$(document).ready(function() {
var newElem = $("<div/>").css("border", "thick solid red");
$("div.drow").wrapAll(newElem);
});
</script>
...
这个脚本中唯一的变化是使用了wrapAll方法。你可以在图 7-8 中看到效果。
图 7-8 。使用 wrapAll 方法
新元素用于将一个公共父元素插入到所选元素中,这样 HTML 就转换成这样:
...
<div class="dtable">
<div style="...style properties...">
<div id="row1" class="drow">
...
</div>
<div id="row2" class="drow">
</div>
</div>
</div>
...
使用wrapAll方法时要小心。如果所选元素尚未共享一个公共父元素,则新元素将作为父元素插入到第一个所选元素中。然后,jQuery 将所有其他选定的元素移动到第一个元素的兄弟元素。清单 7-13 包含了一个演示这种行为的脚本。
清单 7-13 。在没有公共父级的元素上使用 wrapAll
...
<script type="text/javascript">
$(document).ready(function() {
var newElem = $("<div/>").css("border", "thick solid red");
$("img").wrapAll(newElem);
});
</script>
...
我选择了文档中的img元素,它们都没有一个公共的父元素。你可以在图 7-9 中看到这个脚本的效果。新的div元素已经作为 aster 图像的父元素插入到文档中,所有其他图像都作为兄弟元素插入。
图 7-9 。对不共享公共父级的元素使用 wrapAll
包装元素的内容
wrapInner方法 将元素包装在jQuery对象中元素的内容周围,如清单 7-14 所示。
清单 7-14 。使用 wrapInner 方法
...
<script type="text/javascript">
$(document).ready(function() {
var newElem = $("<div/>").css("border", "thick solid red");
$(".dcell").wrapInner(newElem);
});
</script>
...
wrapInner方法在jQuery对象中的元素和它们的直接子元素之间插入新元素。在脚本中,我选择了属于dcell类的元素,并用一个新的div元素包装它们的内容。你可以在图 7-10 中看到效果。
图 7-10 。使用 wrapInner 方法
还可以通过使用append方法达到wrapInner方法的效果。仅供参考,下面是等效的脚本:
...
<script type="text/javascript">
$(document).ready(function() {
var newElem = $("<div/>").css("border", "thick solid red");
$(".dcell").each(function(index, elem) {
$(elem).append(newElem.clone().append($(elem).children()));
});
});
</script>
...
我并不建议您使用这种方法(wrapInner方法更容易阅读,也更方便),但是我认为这是一个很好的例子,说明了如何使用 jQuery 以不同的方式执行相同的任务。
使用函数包装元素
您可以向wrap和wrapInner方法传递一个函数来动态生成元素。为每个选定的元素调用该函数,并向其传递当前元素索引。特殊变量this被设置为要处理的元素。清单 7-15 中的脚本展示了如何动态包装元素。
清单 7-15 。动态包装元素
...
<script type="text/javascript">
$(document).ready(function() {
$(".drow").wrap(function(index) {
if ($(this).has("img[src*=rose]").length > 0) {
return $("<div/>").css("border", "thick solid blue");;
} else {
return $("<div/>").css("border", "thick solid red");;
}
});
});
</script>
...
在这个例子中,我使用一个带有wrap方法的函数,根据每个所选元素的后代定制新的父元素。你可以在图 7-11 中看到这个脚本的效果。
图 7-11 。使用 wrap 方法和函数动态生成父元素
插入兄弟元素
jQuery 还提供了一组方法,将元素作为现有元素的兄弟元素插入到文档中,如表 7-4 中所述。
表 7-4 。插入同级元素的方法
| 方法 | 描述 |
|---|---|
after(HTML)``after(jQuery) | 将指定元素作为下一个兄弟元素插入到jQuery对象中的每个元素。 |
before(HTML)``before(jQuery) | 将指定元素作为前一个兄弟元素插入到jQuery对象的每个元素中。 |
insertAfter(HTML)``insertAfter(jQuery) | 将元素插入到jQuery对象中,作为参数中指定的每个元素的下一个兄弟元素。 |
insertBefore(HTML)``insertBefore(jQuery) | 将元素插入到jQuery对象中,作为参数中指定的每个元素的前一个兄弟元素。 |
after(function) before(function) | 使用函数动态插入同级。 |
before和after方法遵循您在文档中插入其他类型元素时看到的相同模式。清单 7-16 包含了两种方法的演示。
清单 7-16 。使用 before 和 after 方法
...
<script type="text/javascript">
$(document).ready(function() {
var orchidElems = $("<div class='dcell'/>")
.append("<img src='orchid.png'/>")
.append("<label for='orchid'>Orchid:</label>")
.append("<input name='orchid' value='0' required />");
var lilyElems = $("<div class='dcell'/>")
.append("<img src='lily.png'/>")
.append("<label for='lily'>Lily:</label>")
.append("<input name='lily' value='0' required />");
$(orchidElems).add(lilyElems).css("border", "thick solid red");
$("#row1 div.dcell").after(orchidElems);
$("#row2 div.dcell").before(lilyElems);
});
</script>
...
在这个脚本中,我为兰花和百合创建了新的元素集,并将它们与before和after方法一起使用,将它们作为兄弟元素插入到dcell类中的每个元素中。兰花元素作为row1中所有元素的下一个兄弟元素插入,而百合元素作为row2中所有元素的前一个兄弟元素插入。你可以在图 7-12 中看到这个脚本的效果。
图 7-12 。使用 before 和 after 元素创建同级
从 jQuery 对象插入同级
insertAfter和insertBefore方法在jQuery对象中插入元素,作为方法参数中元素的下一个或上一个兄弟元素。这与after和before方法的功能相同,但是jQuery对象和参数之间的关系是相反的。清单 7-17 显示了这些方法的使用。该脚本创建了相同的效果,如图 7-12 所示。
清单 7-17 。使用 insertAfter 和 InsertBefore 方法
...
<script type="text/javascript">
$(document).ready(function() {
var orchidElems = $("<div class='dcell'/>")
.append("<img src='orchid.png'/>")
.append("<label for='orchid'>Orchid:</label>")
.append("<input name='orchid' value='0' required />");
var lilyElems = $("<div class='dcell'/>")
.append("<img src='lily.png'/>")
.append("<label for='lily'>Lily:</label>")
.append("<input name='lily' value='0' required />");
$(orchidElems).add(lilyElems).css("border", "thick solid red");
orchidElems.insertAfter("#row1 div.dcell");
lilyElems.insertBefore("#row2 div.dcell");
});
</script>
...
使用函数插入兄弟节点
您可以使用带有after和before方法的函数动态插入兄弟元素,就像父元素和子元素一样。清单 7-18 包含了一个动态生成兄弟元素的例子。
清单 7-18 。用函数动态生成兄弟元素
...
<script type="text/javascript">
$(document).ready(function() {
$("#row1 div.dcell").after(function(index, html) {
if (index == 0) {
return $("<div class='dcell'/>")
.append("<img src='orchid.png'/>")
.append("<label for='orchid'>Orchid:</label>")
.append("<input name='orchid' value='0' required />")
.css("border", "thick solid red");
} else if (index == 1) {
return $("<div class='dcell'/>")
.append("<img src='lily.png'/>")
.append("<label for='lily'>Lily:</label>")
.append("<input name='lily' value='0' required />")
.css("border", "thick solid red");
}
});
});
</script>
...
在这个脚本中,当正在处理的元素的索引是0或1时,我使用index参数来生成兄弟元素。你可以在图 7-13 中看到这个脚本的效果。
图 7-13 。使用函数添加同级元素
更换元件
您可以使用表 7-5 中描述的方法将一组元素替换为另一组元素。
表 7-5 。包装元件的方法
| 方法 | 描述 |
|---|---|
replaceWith(HTML)``replaceWith(jQuery) | 用指定的内容替换jQuery对象中的元素。 |
replaceAll(jQuery) replaceAll(HTMLElement[]) | 用jQuery对象中的元素替换参数指定的元素。 |
replaceWith(function) | 使用函数动态替换jQuery对象中的元素。 |
除了jQuery对象和参数的角色颠倒之外,replaceWith和replaceAll方法的工作方式相同。清单 7-19 展示了这两种方法。
清单 7-19 。使用 replaceWith 和 replaceAll 方法
...
<script type="text/javascript">
$(document).ready(function() {
var newElems = $("<div class='dcell'/>")
.append("<img src='orchid.png'/>")
.append("<label for='orchid'>Orchid:</label>")
.append("<input name='orchid' value='0' required />")
.css("border", "thick solid red");
$("#row1").children().first().replaceWith(newElems);
$("<img src='carnation.png'/>").replaceAll("#row2 img")
.css("border", "thick solid red");
});
</script>
...
在这个脚本中,我使用replaceWith方法用新内容替换row1 div元素的第一个子元素(这具有用兰花替换紫苑的效果)。我还使用了replaceAll方法来替换所有的img元素,它们是带有康乃馨图像的row2的后代。你可以在图 7-14 中看到这个脚本的效果。
图 7-14 。用 replaceWith 和 replaceAll 方法替换内容
使用函数替换元素
您可以通过向replaceWith方法传递一个函数来动态替换元素。这个函数没有传递任何参数,但是变量this被设置为正在处理的元素。清单 7-20 提供了一个演示。
清单 7-20 。使用函数替换元素
...
<script type="text/javascript">
$(document).ready(function() {
$("div.drow img").replaceWith(function() {
if (this.src.indexOf("rose") > -1) {
return $("<img src='carnation.png'/>").css("border", "thick solid red");
} else if (this.src.indexOf("peony") > -1) {
return $("<img src='lily.png'/>").css("border", "thick solid red");
} else {
return $(this).clone();
}
});
});
</script>
...
在这个脚本中,我根据src属性替换了img元素。如果src属性包含rose,那么我用一个显示carnation.png的元素替换img元素。如果src属性包含peony,那么我用一个显示lily.png的元素替换这个元素。两个替换元素都有一个红色边框来突出显示它们的位置。
对于所有其他元素,我返回正在处理的元素的克隆,其效果是用元素本身的副本替换元素。你可以在图 7-15 中看到效果。
图 7-15 。使用函数替换元素
提示如果你不想替换一个元素,那么你可以简单的返回一个克隆体。如果不克隆元素,jQuery 最终会完全删除元素。当然,您可以通过缩小选择范围来避免这个问题,但这并不总是一个选项。
移除元素
为了补充插入和替换元素,jQuery 提供了一组从 DOM 中移除元素的方法,如表 7-6 中所述。
表 7-6 。移除元素的方法
| 方法 | 描述 |
|---|---|
detach() detach(selector) | 从 DOM 中移除元素。与元素相关联的数据被保留。 |
empty() | 从jQuery对象的每个元素中删除所有子节点。 |
remove() remove(selector) | 从 DOM 中移除元素。随着元素被移除,与元素相关联的数据被破坏。 |
unwrap() | 移除jQuery对象中每个元素的父元素。 |
清单 7-21 展示了如何使用remove元素从 DOM 中移除元素。
清单 7-21 。用 remove 方法从 DOM 中移除元素
...
<script type="text/javascript">
$(document).ready(function() {
$("img[src*=daffodil], img[src*=snow]").parent().remove();
});
</script>
...
这个脚本选择src属性包含daffodil和snow的img元素,获取它们的父元素,然后删除它们。如果你传递一个选择器给remove方法,你可以过滤你移除的元素,如清单 7-22 所示。
清单 7-22 。使用选择器过滤要移除的元素
...
<script type="text/javascript">
$(document).ready(function() {
$("div.dcell").remove(":has(img[src*=snow], img[src*=daffodil])");
});
</script>
...
这两个脚本具有相同的效果,如图图 7-16 所示。
图 7-16 。从 DOM 中移除元素
提示从
remove方法返回的jQuery对象包含原始的一组选定元素。换句话说,元素的移除不会反映在方法结果中。
分离元素
detach方法的工作方式与remove方法相同,只是保留了与元素相关的数据。我在第八章的中解释了数据与元素的关联,但是对于这一章来说,如果你想在文档的其他地方插入元素,知道这通常是最好的方法就足够了。清单 7-23 显示了正在使用的detach方法。
清单 7-23 。使用 detach 方法移除元素,同时保留关联的数据
...
<script type="text/javascript">
$(document).ready(function() {
$("#row2").append($("img[src*=aster]").parent().detach());
});
</script>
...
这个脚本分离出img元素的父元素,该元素的src属性包含aster。然后使用我在本章前面描述的append方法将元素插回到文档中。我倾向于不用这种方法,因为用append不用detach效果一样。您可以重写清单中的关键语句,如下所示:
...
$("#row2").append($("img[src*=aster]").parent());
...
你可以在图 7-17 中看到脚本的效果。
图 7-17 。使用分离元素
清空元素
empty方法从jQuery对象的元素中移除任何后代和文本。元素本身被留在文档中,如清单 7-24 所示。
清单 7-24 。使用空方法
...
<script type="text/javascript">
$(document).ready(function() {
$("#row1").children().eq(1).empty().css("border", "thick solid red");
});
</script>
...
在这个脚本中,我选择索引 1 处的row1元素的子元素,并调用empty方法。为了让变化更加明显,我使用css方法添加了一个边框。你可以在图 7-18 中看到效果。
图 7-18 。使用空方法
展开元素
unwrap方法移除jQuery对象中元素的父元素。所选元素成为其祖父元素的子元素。清单 7-25 显示了正在使用的unwrap方法。
清单 7-25 。使用展开方法
...
<script type="text/javascript">
$(document).ready(function () {
$("div.dcell").unwrap();
});
</script>
...
在这个脚本中,我选择了属于dcell类的div元素,并调用了unwrap方法。这具有移除row1和row2元素的效果,如图图 7-19 所示。
图 7-19 。使用展开方法
摘要
在本章中,我向您展示了如何使用 jQuery 来操作 DOM。我向您展示了如何创建新元素,以及将元素(新的或现有的)作为子元素、父元素和兄弟元素插入 DOM 的许多不同方式。我还向您展示了如何在 DOM 中移动元素以及如何完全移除元素。在第八章中,我将向您展示如何使用 jQuery 来操作 DOM 中的元素。