在 DOM 操作中,有时你需要从一个容器元素出发,找到它内部所有层级中符合某种条件的元素——不管这些元素嵌套了多深。find() 方是为此设计的,它会从被选元素开始,沿 DOM 树向下递归搜索,直到找出所有匹配的后代元素。
find() 和 children() 经常被放在一起比较。两者的关键区别在于遍历深度:children() 只下探一级,仅返回直接子元素;而 find() 会一直向下穿透整个后代层级,子元素、孙子元素、曾孙元素等全部覆盖。这个差异看似细微,在使用中却决定了你的代码是精准还是失控。
为什么在深层搜索时我选择 find() 而不是反复链式调用 children()?
嵌套层级深、结构不可控时,链式 .children().children() 不仅写起来冗长,还对 DOM 结构有强依赖——HTML 结构一变动,代码就失效。find() 则解耦了这段关系,只需传入目标选择器,jQuery 自动遍历到底。这种写法更健壮,维护成本也更低。
语法
$(selector).find(filter)
filter 参数是必需的,它用来限定后代元素的匹配条件。这个参数可以是 CSS 选择器表达式、DOM 元素对象或 jQuery 对象。如果想要选中所有后代元素,可以使用通配选择器 "*":
$(selector).find("*")
课程知识要点
-
递归遍历全部后代:
find()不限于子级,会一直向下搜索直到叶子节点,找到所有符合过滤条件的后代。 -
必须提供 filter 参数:调用
find()时必须传入筛选条件,这与children()可不传参不同。 -
通配符 * 获取所有后代:传入
"*"可以获取选中元素下所有层级的全部后代元素,适合调试或批量操作。 -
支持多选择器组合:用逗号分隔多个选择器表达式,可以一次性查找多种类型的后代,一次调用完成复合检索。
-
与 children() 的职责边界:需要严格限定在直接子元素层级时用
children(),需要跨层级搜索时用find(),选对方法能避免误伤其他元素。
示例一:查找指定后代元素
这个例子展示 find() 的基本用法——从 id 为 container 的 div 出发,找到它内部所有的 ul 元素并更改样式。注意 ul 被嵌套在多层结构里,children() 无法触及,但 find() 能够穿透查找。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>find() 基础搜索 · 编程学习</title>
<style>
.main * {
display: block;
font-size: 18px;
position: relative;
border: 2px solid #333;
color: #333;
padding: 10px;
margin: 15px;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
function searchDescendants() {
$(document).ready(function () {
// 从 #container 内部找出所有 ul 后代
$("#container").find("ul").css({
"font-size": "28px",
"color": "#1a73e8",
"border": "6px dashed #1a73e8"
});
});
}
</script>
</head>
<body class="main">
body
<div id="container">
容器 div
<div>
内层 div
<ul>
第一层 ul
<h2>
标题 h2
<ul>
第二层 ul(孙子级)
<p>段落元素</p>
</ul>
</h2>
</ul>
</div>
</div>
<button onclick="searchDescendants()">查找所有 ul 后代</button>
</body>
</html>
点击按钮后,两个 ul 元素——一个在较浅的层级,一个被嵌套在 h2 内部——都会应用新样式。find() 跨越了中间的多层节点,直接定位到了目标。
示例二:同时查找多种后代元素
在复杂页面中,有时你需要一次性找出容器内多种类型的后代。下面的代码用逗号分隔选择器,同时查找 div、ul 和 p 元素,一次性为它们统一样式。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>find() 多选择器搜索 · 编程学习</title>
<style>
.main * {
display: block;
font-size: 18px;
position: relative;
border: 2px solid #333;
color: #333;
padding: 10px;
margin: 15px;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
function searchMultiple() {
$(document).ready(function () {
// 同时查找 div、ul、p 三种后代元素
$("#container").find("div,ul,p").css({
"color": "#d93025",
"border": "6px dashed #d93025"
});
});
}
</script>
</head>
<body class="main">
body
<div id="container">
容器 div
<div>
内层 div
<ul>
ul 列表
<h2>
标题 h2(未被选中)
<p>段落元素</p>
</h2>
</ul>
</div>
</div>
<button onclick="searchMultiple()">查找多种后代</button>
</body>
</html>
点击后,所有 div、ul 和 p 后代都会应用红色虚线边框。h2 因为不在选择器列表里,样式不变。这种多选择器组合查询在需要批量处理多种同类组件时非常高效。
示例三:使用通配符获取全部后代
调试阶段或者需要为某个容器下所有元素统一添加轮廓线时,"*" 通配符就很实用。它会返回选中元素下的每一个后代节点,不论标签类型。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>find() 全后代搜索 · 编程学习</title>
<style>
.main * {
display: block;
font-size: 18px;
position: relative;
border: 2px solid #333;
color: #333;
padding: 10px;
margin: 15px;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
function searchAll() {
$(document).ready(function () {
// * 选择器返回所有后代元素
$("#container").find("*").css({
"color": "#1a73e8",
"border": "4px dashed #1a73e8"
});
});
}
</script>
</head>
<body class="main">
body
<div id="container">
容器 div
<div>
内层 div
<h2>
标题 h2
<p>段落元素</p>
</h2>
</div>
</div>
<button onclick="searchAll()">显示全部后代</button>
</body>
</html>
点击按钮后,容器内除了文本节点外,所有元素节点都被蓝色虚线高亮。这在排查 DOM 结构时能让你一眼看清元素边界,是开发调试阶段的实用手段。
个人经验与实用建议
在日常开发中,find() 的滥用也会带来问题。因为它是全局递归搜索,如果在非常大的 DOM 树上使用宽松的选择器(如 ".item"),性能消耗不可忽视。我的习惯是:先缩小搜索范围,再调用 find()。也就是说,尽量用一个更具体的父级选择器来限定出发点,而不是直接在 $(document) 上调用 find()。
如果项目中有大量重复的 find() 调用,不妨把查找结果缓存到一个变量里。jQuery 每次执行 find() 都需要遍历 DOM,缓存结果可以避免重复查找,在循环或高频触发的事件中尤其明显。这个细节虽小,对页面流畅度的帮助却很大。