13.3 遍历DOM

我们已经了解了如何使用jQuery和基本的CSS语法来选择页面元素,例如$('p'),它可以选择页面上所有的段落。一旦你选择了元素,可以对它们做很多事情,例如,添加或删除一个类、更改一个CSS属性,或者让该元素消失。但是,有时候,你可能想要找到和最初的选择相关的其他的页面元素。用JavaScript的语言来描述,这叫做遍历DOM。

当你想要给一个元素添加一个事件,但随后想要对另一个元素做一些事情的时候,经常需要遍历DOM。例如,假设你有一个<div>标签,其ID为gallery,这个div包含了一系列的缩略图像。当访问者用鼠标单击该div的时候,你想要缩略图做些事情:缩小、放大、晃动或者类似的事情。添加给该<div>标签的事件如下所示:


$('#gallery').click(function(){

});//end click


在该函数内部,你需要添加程序代码来实现图像动画。因此,当用户单击了div,你想要对图像做些事情。在上面的代码中,你只是选择了该<div>标签,并且在函数$(this)内部将引用该div(如果这对你来说很新颖的话,请翻到4.10.2节回顾一下什么是$(this))。因此,<div>标签是click函数中选择的元素,你需要找到该div中的图像。幸运的是,jQuery恰好提供了这样的解决方案:.find()函数。它的作用是,通过在当前选择中搜索和给定选择器匹配的其他标签,来产生一个新的页面元素选择。因此,你可以通过添加如下粗体所示的代码,在该div内部选择图像:


$('#gallery').click(function(){

$(this).fnd('img');

});//end click


$(this). find('img')创建了一个新的元素选择,$(this)引用该div,然后,.find('img')查找该div中的每一幅图像。当然,这段代码没有对新的选择做任何事情,但是,你可以添加在上一章中所学到过的任何效果。例如,假设你想要图像临时淡出视线,然后再次淡入到视线。可以使用如下代码:


$('#gallery').click(function(){

$(this).fnd('img').fadeTo(500,.3).fadeTo(250,1);

});//end click


正如在6.1.1节所介绍的,fadeTo()函数接收一个duration值和一个opacity值作为参数。因此,这段代码首先在500毫秒内将所有图像淡出到30%的不透明度,然后,在250毫秒内将其淡入回到100%的不透明度(参见教程chapter13文件夹下的find.html文件,可以看看这一效果的作用)。

实际上,遍历DOM是如此常见的任务,以至于jQuery提供了众多的函数来帮助你选择元素,然后找到和初次选择的元素相关的其他元素。为了更好地理解这些函数是如何工作的,我们使用图13-3中的一小段HTML来表示:http://api.jquery.com/category/manipulation/。它是一个ID为gallery的<div>标签,其中包含了4个链接,每个链接都包含一幅图像。

正如在4.1.5节所介绍的,你可以使用家庭的关系来描述页面上的标签之间的关系。例如,在图13-3中,<div>标签是<a>标签的父亲,并且,每个<a>标签是位于其中的<img>标签的父亲。相反,<a>标签是<div>标签的孩子,每个<a>标签是其他<a>标签的兄弟。每个<img>标签都是包围它们的<a>标签的孩子,并且,由于每个<a>中没有其他的标签,因此<img>标签没有兄弟。

13.3 遍历DOM - 图1

图 13-3 当你用jQuery进行选择时,例如,给一个元素添加一个事件处理程序,如这里的图中描述的<a>标签,你常常想要对选择的元素相关的另一个元素执行操作(例如,给div标签添加一个边框,或者变换img标签)。jQuery的DOM遍历函数可以帮忙

下面是最常用的几个jQuery DOM遍历函数:

·. find()。找到当前选择中的特定元素。你可以从一个jQuery选择开始,添加.find()并将其传递给一个CSS选择器,代码如下所示:


$('#gallery').find('img')


这段代码找到gallery div中的所有图像。当然,你可以使用诸如$('#gallery img')的一个子孙选择器,来实现同样的目标。正如上面所提到的,当你已经有一个选择,并且也已经对它做了一些事情的时候(例如,添加了一个click事件),在这种情况下,你更可能使用.find()来创建一个新的选择以对其执行操作。

你使用.find()来选择当前选择的一个子孙(即位于一个标签中的另一个标签)。因此,在图13-3所描述的例子中,我们可以在包含了div的一个选择上使用.find(),以选择<a>标签或<img>标签。

注意:查看13.1.4节了解.find()所带来的巨大的性能好处。和使用一个子孙选择器相比,它通常是一种更快的选择元素的方式。

·children()类似于.find()。它也接收一个选择器作为参数,但是,它将自己的选择限制在当前选择的直接孩子上。例如,假设你有一个div标签,它包含了一系列的其他div。当你单击main div时,它显示出之前隐藏的div,并且在其周围添加一个红色的边框。假设你使用.find()函数来实现这一目标,代码如下所示:


$('#mainDiv').click(function(){

$(this).find('div').show().css('outline','red 2px solid');

});


如果m a i n d i v中的一个d i v其中也有一个d i v标签的话,问题就出现了。.find('div')找到所有的div标签,甚至包括div之中的其他div。你可能最终得到一个页面,其中所有的div都用边框圈了起来,而你想要的只是让main div直接包含的孩子div带上边框。为了解决这个难题,你可以使用.children()重新编写上面的代码,如下所示:


$('#mainDiv').click(function(){

$(this).children('div').show().css('outline','red 2px solid');

});


现在,这段代码只是找到main div的直接孩子的那些div,并且避免了孩子div之中可能存在的任何div。

·. parent()。.find()找到当前元素中的元素,.parent()向上遍历DOM,找到当前标签的父亲标签。这可能会很方便,例如,要给图13-3中的<a>标签添加一个hover事件,但是,你想要对<div>标签执行操作(例如,给该div添加一个边框或背景颜色)。在这种情况下,你要使用.parent()来找到div并对其应用操作,如下所示:


$('#gallery a').hover(

function(){

//add outline to link

$(this).css('outline',’2px solid red');

//add background color to div

$(this).parent().css('backgroundColor','white');

},

function(){

//remove outline from link

$(this).css('outline',’');

//remove background color from div

$(this).parent().css('backgroundColor',’');

}

);//end hover


在这个例子中,在一个链接上悬停鼠标光标,就会在该链接周围添加一个边框,然后,选择该链接的父亲元素(div)并且对其应用一种背景颜色。当鼠标光标离开该链接的时候,将会删除边框和背景颜色(参见5.4.2节,以了解关于.hover()事件的更多信息)(参见教程chapter13文件夹下的parent.html文件,以了解使用这个函数的一个例子)。

·. closest()找到和一个特定选择器匹配的最近的祖先元素。和.parent()不同,.parent()只是找到当前标签的直接父亲元素,而.closest()接收一个选择器作为参数,并且找到匹配该选择器的最近的祖先元素。例如,在图13-3中,每个<a>标签中都有一幅图像,换句话说,<a>标签是图像的父亲元素。然而,如果你想要选择包含了<a>标签的<div>标签(HTML链级中更高一层的一个祖先元素),该怎么做呢?可以像下面这样使用.closest():


1$('#gallery img').click(function(){

2$(this).css('outline',’2px red solid');

3$(this).closest('div').css('backgroundColor','white');

4});//end click


在第3行中,$(this)引用<img>标签,.closest('div')表示找到是<div>的一个最近的祖先元素。最近的祖先元素是<a>标签,但是,由于它不是一个div, jQuery会略过它并找到下一个祖先元素,依次类推,直到找到一个<div>。

·当你想要选择与当前选择相同级别的一个元素的时候,.siblings()函数很方便。以图13-3为例,当一个访问者单击一个链接,你想要让所有其他的链接都慢慢地淡出并淡入视线中。在这个例子中,click事件应用于一个link标签,但是,你想要对div中所有其他的链接执行这一效果。换句话说,你从一个链接开始,但是想要选择所有的兄弟链接。可以像下面这样来做到这点:


1$('#gallery a').click(function(){

2$(this).siblings().fadeTo(500,.3).fadeTo(250,1);

3});//end click


在上面的代码中,$(this)引用单击的链接,因此,.siblings()选择该div中所有其他的链接。

.siblings()函数还接收一个参数,即一个选择器的名称,来将选择的兄弟元素限定为某种类型的标签。例如,假设在图13-3所示的<div>标签的内部,在链接的前面有一个标题和介绍性的段落。由于标题和段落都在<div>标签中,与所有的<a>标签在一起,因此它们也是<a>标签的兄弟标签。换句话说,使用上面的代码,单击一个链接也会导致所有的标题和段落淡出后再淡入回视线中。要将这种效果仅限于其他链接,我们可以重新编写上面的第2行代码,如下所示:


$(this).siblings('a').fadeTo(500,.3).fadeTo(250,1);


siblings('a')内部的'a'把选择限定为仅仅是<a>标签的那些兄弟元素。参见教程chapter13文件夹下的siblings.html文件,看看这个函数是如何工作的。

·. next()会找到当前选择的下一个兄弟元素。5.6节的“一页的FAQ”教程中看到过这个函数的使用方法。在该教程中,单击一个问题将会打开并随后关闭一个<div>标签,其中包含了该问题的解答。每个问题都使用一个<h2>标签来表示,每个解答用一个div标签表示,并且紧跟在该<h2>标签之后。标题和div是兄弟,但是,它们也是该页面上的其他的问题和解答的兄弟元素。因此,当单击一个标题的时候,你必须选择相邻的兄弟(换句话说,下一个兄弟元素)。和.siblings()一样,.next()接收一个可选的选择器,以便你可以将选择限定为特定类型的、相邻的兄弟(参见教程chapter05文件夹下的complete_faq.html文件,以查看使用.next()的一个示例)。

·. prev()像.next()一样工作,只不过它选择的是紧邻的前一个兄弟元素。

注意:要了解更多的用来遍历DOM的jQuery函数,访问http://api.jquery.com/category/traversing/。