jQueryDOM遍历方法详解

jQuery DOM遍历方法允许您在DOM树中导航、查找和选择元素。这些方法基于当前选择的元素集,在DOM树中向上、向下或水平移动。

DOM遍历概述

jQuery提供了一组强大的DOM遍历方法,使您能够轻松地在文档对象模型(DOM)树中移动和查找元素。这些方法从当前匹配的元素集开始,根据您的要求返回新的元素集。

document (文档)
<html>
<head>
<title>页面标题</title>
<body>
<div id="container">
<h1>标题</h1>
<p class="intro">介绍段落</p>
<div class="content">
<p>内容段落1</p>
<p>内容段落2</p>
<ul>
<li>列表项1</li>
<li>列表项2</li>
<li>列表项3</li>
重要概念

所有的jQuery遍历方法都从一个jQuery对象开始,并返回一个新的jQuery对象,这允许进行链式操作。

语法模式: $(selector).traversalMethod()

向上遍历(父元素)

这些方法用于在DOM树中向上移动,查找当前元素的父元素或祖先元素。

parent()

获取当前匹配元素集合中每个元素的直接父元素。

$(selector).parent([filter])
示例:
// 获取所有段落的直接父元素
$("p").parent();

// 获取class为"intro"的段落的直接父元素
$("p.intro").parent();

// 获取所有段落的直接父元素,但只返回div元素
$("p").parent("div");

// 获取id为"item1"的列表项的直接父元素
$("#item1").parent();
父元素
↑ parent()
当前元素

parents()

获取当前匹配元素集合中每个元素的所有祖先元素(一直到文档根元素)。

$(selector).parents([filter])
示例:
// 获取所有段落的所有祖先元素
$("p").parents();

// 获取所有段落的祖先元素,但只返回div元素
$("p").parents("div");

// 获取class为"child"的元素的所有祖先元素
$(".child").parents();

// 获取所有段落的所有祖先元素,直到遇到body元素
$("p").parents().not("html");
曾祖父元素
↑ parents()
祖父元素
↑ parents()
父元素
↑ parents()
当前元素

parentsUntil()

获取当前匹配元素集合中每个元素的所有祖先元素,直到遇到匹配选择器的元素为止(不包含匹配的元素)。

$(selector).parentsUntil([selector][, filter])
示例:
// 获取所有段落的祖先元素,直到遇到div元素
$("p").parentsUntil("div");

// 获取id为"item1"的元素的祖先元素,直到遇到class为"container"的元素
$("#item1").parentsUntil(".container");

// 获取所有段落的祖先元素,直到遇到body元素,且只返回div元素
$("p").parentsUntil("body", "div");
停止元素
↑ parentsUntil()
祖父元素
↑ parentsUntil()
父元素
↑ parentsUntil()
当前元素

closest()

从当前元素开始,沿DOM树向上查找匹配选择器的第一个祖先元素(包含当前元素本身)。

$(selector).closest(selector[, context])
示例:
// 获取离每个段落最近的div祖先元素
$("p").closest("div");

// 获取离当前点击元素最近的li祖先元素
$(document).on("click", function(event) {
    $(event.target).closest("li");
});

// 获取离每个段落最近的具有data-role属性的祖先元素
$("p").closest("[data-role]");

// 在指定上下文中查找最近的匹配元素
$("span").closest("li", "#list-container");
closest() vs parents()
  • closest() 从当前元素开始查找,返回第一个匹配的祖先元素
  • parents() 返回所有匹配的祖先元素
  • closest() 包含当前元素本身,如果它匹配选择器
  • closest() 只返回0或1个元素,parents() 可能返回多个元素

offsetParent()

获取第一个匹配元素的最近定位祖先元素(position为relative、absolute、fixed或sticky)。

$(selector).offsetParent()
示例:
// 获取第一个段落的定位父元素
$("p:first").offsetParent();

// 获取所有具有绝对定位的元素的定位父元素
$("[style*='position: absolute']").offsetParent();

// 用于计算相对于定位父元素的偏移量
var offset = $("#element").offset();
var parentOffset = $("#element").offsetParent().offset();
var relativeOffset = {
    top: offset.top - parentOffset.top,
    left: offset.left - parentOffset.left
};

向下遍历(后代元素)

这些方法用于在DOM树中向下移动,查找当前元素的子元素或后代元素。

children()

获取当前匹配元素集合中每个元素的直接子元素。

$(selector).children([filter])
示例:
// 获取div的所有直接子元素
$("div").children();

// 获取id为"container"的元素的所有直接子元素
$("#container").children();

// 获取div的所有直接子元素,但只返回p元素
$("div").children("p");

// 获取ul的所有直接子元素,即所有li元素
$("ul").children("li");
当前元素
↓ children()
子元素1
子元素2
子元素3

find()

获取当前匹配元素集合中每个元素的后代元素中匹配指定选择器的元素。

$(selector).find(selector)
示例:
// 查找div内的所有span元素
$("div").find("span");

// 查找id为"container"的元素内的所有p元素
$("#container").find("p");

// 查找所有具有class="active"的元素
$("ul").find(".active");

// 查找div内的所有后代元素
$("div").find("*");

// 多种选择器组合
$("#form").find("input[type='text'], input[type='email']");
当前元素
↓ find()
子元素
孙元素
曾孙元素
注意: find() 是jQuery中最常用的遍历方法之一,它允许您深入DOM树查找匹配的元素。

contents()

获取当前匹配元素集合中每个元素的子节点,包括文本节点和注释节点。

$(selector).contents()
示例:
// 获取div的所有子节点(包括文本节点)
$("div").contents();

// 查找iframe的内容
$("iframe").contents().find("body");

// 过滤文本节点
$("#element").contents().filter(function() {
    return this.nodeType === Node.TEXT_NODE;
});

// 获取script元素的内容
$("script").contents();
重要: contents()children() 不同,它返回所有子节点,包括文本节点和注释节点,而 children() 只返回元素节点。

水平遍历(兄弟元素)

这些方法用于在DOM树中水平移动,查找当前元素的兄弟元素。

siblings()

获取当前匹配元素集合中每个元素的所有兄弟元素(不包括元素本身)。

$(selector).siblings([filter])
示例:
// 获取所有段落的兄弟元素
$("p").siblings();

// 获取id为"item2"的元素的所有兄弟元素
$("#item2").siblings();

// 获取所有h2元素的兄弟元素,但只返回p元素
$("h2").siblings("p");

// 获取当前活动元素的兄弟元素
$(".active").siblings();
兄弟元素1
兄弟元素2
当前元素
兄弟元素3
兄弟元素4

next()

获取当前匹配元素集合中每个元素的紧邻的下一个兄弟元素。

$(selector).next([filter])
示例:
// 获取每个段落的下一个兄弟元素
$("p").next();

// 获取id为"item1"的元素的下一个兄弟元素
$("#item1").next();

// 获取h2元素的下一个兄弟元素,但只返回p元素
$("h2").next("p");

// 获取当前活动元素的下一个兄弟元素
$(".active").next();
兄弟元素1
当前元素
→ next()
下一个兄弟元素
兄弟元素3

prev()

获取当前匹配元素集合中每个元素的紧邻的上一个兄弟元素。

$(selector).prev([filter])
示例:
// 获取每个段落的上一个兄弟元素
$("p").prev();

// 获取id为"item3"的元素的上一个兄弟元素
$("#item3").prev();

// 获取h2元素的上一个兄弟元素,但只返回p元素
$("h2").prev("p");

// 获取当前活动元素的上一个兄弟元素
$(".active").prev();
兄弟元素1
← prev()
当前元素
下一个兄弟元素
兄弟元素3

nextAll()

获取当前匹配元素集合中每个元素之后的所有兄弟元素。

$(selector).nextAll([filter])
示例:
// 获取每个段落之后的所有兄弟元素
$("p").nextAll();

// 获取id为"item1"的元素之后的所有兄弟元素
$("#item1").nextAll();

// 获取h2元素之后的所有兄弟元素,但只返回p元素
$("h2").nextAll("p");

// 获取当前活动元素之后的所有兄弟元素
$(".active").nextAll();

prevAll()

获取当前匹配元素集合中每个元素之前的所有兄弟元素。

$(selector).prevAll([filter])
示例:
// 获取每个段落之前的所有兄弟元素
$("p").prevAll();

// 获取id为"item3"的元素之前的所有兄弟元素
$("#item3").prevAll();

// 获取h2元素之前的所有兄弟元素,但只返回p元素
$("h2").prevAll("p");

// 获取当前活动元素之前的所有兄弟元素
$(".active").prevAll();

nextUntil()

获取当前匹配元素集合中每个元素之后的所有兄弟元素,直到遇到匹配选择器的元素为止。

$(selector).nextUntil([selector][, filter])
示例:
// 获取段落之后的所有兄弟元素,直到遇到h2元素
$("p").nextUntil("h2");

// 获取id为"item1"的元素之后的所有兄弟元素,直到遇到class为"end"的元素
$("#item1").nextUntil(".end");

// 获取段落之后的所有兄弟元素,直到遇到h2元素,且只返回span元素
$("p").nextUntil("h2", "span");

prevUntil()

获取当前匹配元素集合中每个元素之前的所有兄弟元素,直到遇到匹配选择器的元素为止。

$(selector).prevUntil([selector][, filter])
示例:
// 获取段落之前的所有兄弟元素,直到遇到h2元素
$("p").prevUntil("h2");

// 获取id为"item5"的元素之前的所有兄弟元素,直到遇到class为"start"的元素
$("#item5").prevUntil(".start");

// 获取段落之前的所有兄弟元素,直到遇到h2元素,且只返回span元素
$("p").prevUntil("h2", "span");

过滤方法

这些方法用于从当前匹配的元素集合中筛选出特定的子集。

filter()

从匹配元素集合中筛选出匹配指定选择器或通过函数测试的元素。

$(selector).filter(selector|function|element)
示例:
// 筛选出class为"active"的段落
$("p").filter(".active");

// 筛选出索引为偶数的段落
$("p").filter(":even");

// 使用函数筛选出文本长度大于10的段落
$("p").filter(function() {
    return $(this).text().length > 10;
});

// 筛选出可见的段落
$("p").filter(":visible");

// 筛选出具有特定属性的元素
$("div").filter("[data-id]");

not()

从匹配元素集合中移除匹配指定选择器或通过函数测试的元素。

$(selector).not(selector|function|element)
示例:
// 选择所有段落,除了class为"intro"的
$("p").not(".intro");

// 选择所有段落,除了第一个
$("p").not(":first");

// 使用函数排除文本包含"test"的段落
$("p").not(function() {
    return $(this).text().indexOf("test") !== -1;
});

// 排除隐藏的段落
$("p").not(":hidden");

eq()

从匹配元素集合中获取指定索引位置的元素。

$(selector).eq(index)
示例:
// 获取第一个段落(索引0)
$("p").eq(0);

// 获取第三个段落(索引2)
$("p").eq(2);

// 获取最后一个段落
$("p").eq(-1);

// 获取倒数第二个段落
$("p").eq(-2);

// 链式操作中使用eq
$("div").find("p").eq(0).addClass("first");

first()

获取匹配元素集合中的第一个元素。

$(selector).first()
示例:
// 获取第一个段落
$("p").first();

// 获取第一个div中的第一个段落
$("div").first().find("p").first();

// 为第一个段落添加特殊样式
$("p").first().addClass("first-paragraph");

// 获取第一个可见的段落
$("p:visible").first();

last()

获取匹配元素集合中的最后一个元素。

$(selector).last()
示例:
// 获取最后一个段落
$("p").last();

// 获取最后一个div中的最后一个段落
$("div").last().find("p").last();

// 为最后一个段落添加特殊样式
$("p").last().addClass("last-paragraph");

// 获取最后一个可见的段落
$("p:visible").last();

slice()

从匹配元素集合中获取一个子集,基于指定的索引范围。

$(selector).slice(start[, end])
示例:
// 获取前3个段落(索引0,1,2)
$("p").slice(0, 3);

// 获取从第2个开始的段落(索引1及之后)
$("p").slice(1);

// 获取最后3个段落
$("p").slice(-3);

// 获取索引2到4的段落(索引2,3,4)
$("p").slice(2, 5);

// 获取除第一个和最后一个之外的所有段落
$("p").slice(1, -1);

map()

将当前匹配元素集合中的每个元素传递给函数,并返回包含函数返回值的新jQuery对象。

$(selector).map(callback)
示例:
// 获取所有段落的文本内容数组
var texts = $("p").map(function() {
    return $(this).text();
}).get();

// 获取所有段落中链接的href属性
var links = $("p a").map(function() {
    return $(this).attr("href");
}).get();

// 获取所有可见段落的id
var ids = $("p:visible").map(function() {
    return this.id;
}).get();

// 转换元素集合
var $spans = $("div").map(function() {
    return $("span", this).get();
});
过滤方法比较表
方法 描述 返回元素数量 常用场景
filter() 筛选匹配条件的元素 0个或多个 根据条件选择子集
not() 排除匹配条件的元素 0个或多个 排除特定元素
eq() 选择指定索引的元素 0或1个 选择特定位置的元素
first() 选择第一个元素 0或1个 选择第一个元素
last() 选择最后一个元素 0或1个 选择最后一个元素
slice() 选择索引范围内的元素 0个或多个 选择连续范围的元素
map() 转换元素集合 0个或多个 提取或转换元素数据

链式操作

jQuery的一个强大特性是链式操作,允许您在单个语句中连接多个方法调用。

// 链式操作示例:查找、过滤和操作元素
$("#container")
    .find("p")                    // 查找所有段落
    .filter(".intro")             // 筛选class为"intro"的段落
    .css("color", "red")          // 设置颜色为红色
    .slideUp()                    // 向上滑动隐藏
    .slideDown()                  // 向下滑动显示
    .addClass("highlighted");     // 添加高亮类

// 更复杂的链式操作
$("ul.nav")
    .children("li")               // 获取所有li子元素
    .filter(":first")             // 选择第一个li
    .addClass("first-item")       // 添加类
    .next()                       // 获取下一个兄弟元素
    .addClass("second-item")      // 添加类
    .find("a")                    // 查找内部的a元素
    .css("font-weight", "bold");  // 设置字体粗细

// 条件链式操作
var $items = $(".item")
    .hide()                       // 隐藏所有项
    .filter(".active")            // 筛选活动项
    .show()                       // 显示活动项
    .parent()                     // 获取父元素
    .addClass("has-active");      // 添加类

// 链式操作中的方法组合
$("form")
    .find("input[type='text']")   // 查找文本输入框
    .val("")                      // 清空值
    .addClass("cleared")          // 添加类
    .end()                        // 返回到form元素
    .find("input[type='submit']") // 查找提交按钮
    .prop("disabled", true);      // 禁用按钮
链式操作的优势
  • 代码简洁: 减少代码行数,提高可读性
  • 性能优化: 减少重复的DOM查询
  • 提高效率: 在一个语句中完成多个操作
  • 易于维护: 逻辑组织更清晰

高级遍历方法

这些方法提供了更高级的DOM遍历功能。

end()

结束当前链中最近的一次筛选操作,并将匹配元素集合还原为之前的状态。

$(selector).end()
示例:
// 使用end()返回到前一个元素集合
$("ul.first")
    .find(".item")        // 查找class为item的元素
    .css("color", "red")  // 设置颜色为红色
    .end()                // 返回到ul.first
    .find(".special")     // 查找class为special的元素
    .css("color", "blue"); // 设置颜色为蓝色

// 链式操作中的end()
$("#container")
    .find("p")            // 查找段落
    .addClass("para")     // 添加类
    .end()                // 返回到#container
    .find("div")          // 查找div
    .addClass("box")      // 添加类
    .end()                // 返回到#container
    .addClass("wrapper"); // 添加包装器类

// 多重end()
$("div")
    .find("p")
    .addClass("first")
    .filter(":first")
    .addClass("very-first")
    .end()  // 返回到所有p元素
    .end()  // 返回到所有div元素
    .addClass("container");

add()

将元素添加到匹配元素集合中。

$(selector).add(selector|elements|html)
示例:
// 添加更多元素到当前集合
$("p").add("div").css("color", "red");

// 添加另一个选择器的结果
$("h1").add("h2").addClass("heading");

// 添加特定元素
var $first = $("p:first");
$("p").add($first).addClass("all-and-first");

// 添加新创建的元素
$("div").add("<span>新元素</span>").appendTo("body");

// 添加多个选择器
$("p.intro")
    .add("div.content")
    .add("span.highlight")
    .addClass("selected");

addBack()

将堆栈中的前一个元素集合添加到当前集合中。

$(selector).addBack([selector])
示例:
// 使用addBack()包含前一个集合
$("div")
    .find("p")              // 查找div中的段落
    .addClass("para")       // 为段落添加类
    .addBack()              // 添加div元素到当前集合
    .addClass("container"); // 为div和段落都添加类

// 带选择器的addBack()
$("ul")
    .children("li")         // 获取li子元素
    .filter(":first")       // 选择第一个li
    .addBack("ul")          // 添加ul元素到当前集合
    .css("border", "1px solid red");

// 多重遍历中的addBack()
$("#menu")
    .find("li")             // 查找li元素
    .addClass("item")       // 添加类
    .find("a")              // 查找a元素
    .addClass("link")       // 添加类
    .addBack()              // 添加li元素到当前集合(包含a元素)
    .addBack()              // 添加#menu到当前集合(包含li和a元素)
    .addClass("highlighted");

is()

检查当前匹配元素集合中是否有元素匹配选择器,返回布尔值。

$(selector).is(selector|function|element)
示例:
// 检查是否有段落元素
if ($("#element").is("p")) {
    console.log("这是一个段落");
}

// 检查元素是否可见
if ($("#menu").is(":visible")) {
    console.log("菜单是可见的");
}

// 检查元素是否具有特定类
if ($("#button").is(".active")) {
    console.log("按钮是活动的");
}

// 使用函数检查
if ($("input").is(function() {
    return $(this).val().length > 0;
})) {
    console.log("至少有一个输入框有值");
}

// 事件处理中的is()
$(document).on("click", function(event) {
    if ($(event.target).is("a")) {
        console.log("点击了链接");
    }
});

has()

将匹配元素集合缩减为包含匹配指定选择器的后代的元素。

$(selector).has(selector|element)
示例:
// 选择包含span元素的div
$("div").has("span");

// 选择包含活动列表项的ul
$("ul").has("li.active");

// 选择包含图像的段落
$("p").has("img");

// 选择包含特定元素的li
var $target = $(".target");
$("li").has($target);

// 链式操作中使用has()
$("div")
    .has("p")               // 选择包含段落的div
    .addClass("has-paragraph")
    .find("p")              // 查找这些段落
    .addClass("inside-div");

性能优化技巧

高效使用DOM遍历方法
  • 缓存jQuery对象: 重复使用选择器结果
    // 不好:重复查询DOM
    $("#container").find("p").addClass("first");
    $("#container").find("p").addClass("second");
    
    // 好:缓存jQuery对象
    var $container = $("#container");
    var $paragraphs = $container.find("p");
    $paragraphs.addClass("first");
    $paragraphs.addClass("second");
  • 使用ID选择器: ID选择器是最快的
    // 慢:使用类选择器遍历
    $(".container").find(".item");
    
    // 快:使用ID选择器
    $("#container").find(".item");
  • 缩小上下文范围: 在较小的上下文中查找
    // 慢:在整个文档中查找
    $(".item");
    
    // 快:在特定上下文中查找
    $("#container").find(".item");
  • 使用find()代替上下文选择器:
    // 较慢:上下文选择器
    $("#container .item");
    
    // 较快:使用find()
    $("#container").find(".item");
  • 避免过度遍历: 减少不必要的遍历步骤
    // 过度遍历
    $("#container").children().children().find("p");
    
    // 优化后
    $("#container").find("> * > p");
  • 使用原生JavaScript: 对于简单操作,原生方法更快
    // jQuery
    $("#element").parent();
    
    // 原生JavaScript(更快)
    document.getElementById("element").parentNode;
遍历方法性能比较
方法 性能特点 使用建议
find() 非常高效,内部使用querySelectorAll 首选的后代查找方法
children() 高效,只查找直接子元素 当只需要直接子元素时使用
parent() 高效,直接访问parentNode 查找直接父元素
parents() 中等,需要遍历所有祖先 需要所有祖先时使用
closest() 高效,找到第一个匹配就停止 查找最近的匹配祖先
siblings() 中等,需要筛选兄弟元素 需要所有兄弟时使用
next()/prev() 非常高效,直接访问nextSibling/previousSibling 需要相邻兄弟时使用
filter() 中等,需要测试每个元素 从集合中筛选元素

实时演示

演示DOM结构:

演示标题

介绍段落

内容段落1

内容段落2(活动)

内容段落3

  • 列表项1
  • 列表项2(活动)
  • 列表项3
  • 列表项4
这是一个span元素
选择遍历方法:
遍历结果:
选择方法并点击"执行遍历"查看结果
执行的代码:
// 代码将在这里显示
关键要点
  • jQuery DOM遍历方法允许您在DOM树中导航、查找和选择元素
  • 遍历方法分为三类:向上(父元素)、向下(后代元素)、水平(兄弟元素)
  • 过滤方法用于从当前匹配的元素集合中筛选出特定的子集
  • 链式操作是jQuery的强大特性,允许连接多个方法调用
  • 使用性能优化技巧可以提高页面响应速度
  • 理解不同遍历方法的适用场景和性能特点很重要