jQuery find() 方法怎么用:查找指定元素的写法与示例

jQuery find() 方法怎么用:查找指定元素的写法与示例

jQuery find() 方法怎么用:查找指定元素的写法与示例

在 jQuery 中,find() 用来从一组已有元素出发,查找它们内部符合条件的后代元素。比如,在某个表单中查找所有输入框、在指定卡片中查找按钮,或者在局部容器里定位提示信息。

它最重要的边界是:find() 只查找当前元素的后代,不会把当前元素本身作为结果,也不会查找它的兄弟元素或祖先元素。理解这一点,通常就能避免多数选择范围错误。

一、基本写法

find() 的常见写法如下:

$(选择范围).find(选择器)

参数通常是一个 CSS 选择器字符串。方法返回一个新的 jQuery 对象,其中包含在当前范围内匹配的后代元素。若没有匹配项,仍会返回 jQuery 对象,只是其中元素数量为 0。

下面是一个可运行示例。把代码放进 HTML 文件,并确保能加载 jQuery,即可看到点击按钮后页面显示匹配到的链接数量。

<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <title>find() 基本示例</title>
  <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
</head>
<body>
  <div id="menu">
    <a href="/home">首页</a>
    <div class="group">
      <a href="/docs">文档</a>
    </div>
  </div>

  <button id="count">统计菜单中的链接</button>
  <p id="result"></p>

  <script>
    $("#count").on("click", function () {
      var links = $("#menu").find("a");
      $("#result").text("找到 " + links.length + " 个链接");
    });
  </script>
</body>
</html>

$("#menu") 先选中查找范围,.find("a") 再查找该范围内的所有后代链接。范围中有嵌套容器并不影响查找,深层嵌套的后代也会被纳入结果。

二、find() 查找的范围是什么

DOM 元素之间有父子、后代、兄弟等关系。find() 只沿着当前元素向下查找所有层级的后代,匹配元素可以是子元素、孙元素或更深层级的元素。

<div id="panel" class="target">
  <p class="target">直接子元素</p>
  <section>
    <p class="target">更深层的后代</p>
  </section>
</div>

<script>
  var result = $("#panel").find(".target");
  console.log(result.length); // 2
</script>

虽然 #panel 自己也有 target 类,但它不在 find() 的结果中,因为它是查找起点,而不是起点的后代。若要检查当前元素本身是否符合条件,可以用 is();若要从一组已选元素中筛选,可以用 filter()。

var panel = $("#panel");

console.log(panel.is(".target")); // true:判断 panel 本身
console.log(panel.find(".target").length); // 2:查找 panel 的后代
console.log($(".target").filter("#panel").length); // 1:筛选已有集合

同样,find() 不会向上查找祖先,也不会横向查找兄弟元素。需要向上查找时通常使用 closest() 或 parents();需要查找相邻元素时使用 next()、siblings() 等方法。

三、选择器怎么写

参数可以使用常见 CSS 选择器,例如标签、类、ID、属性选择器、后代组合选择器和伪类。选择器的匹配范围仍受 find() 的起点限制。

var form = $("#registerForm");

var inputs = form.find("input");
var email = form.find("input[type='email']");
var requiredFields = form.find("[required]");
var checkedOptions = form.find("input:checked");
var submitButtons = form.find("button, input[type='submit']");

选择器也可以描述元素之间的关系。例如,下面的选择器会找到范围内 .card 后代中的 .title,不会因为页面其他位置存在同名元素而扩大范围。

var titles = $("#products").find(".card .title");

在语义上,下面两种写法通常表达相同的范围:

var a = $("#products").find(".card .title");
var b = $("#products .card .title");

第一种写法把查找范围明确分成两步,便于把范围对象保存下来并复用。第二种写法是一个完整的选择器。实际项目中可以按可读性选择;当范围由变量、事件目标或组件实例动态决定时,find() 往往更直观。

四、适用场景与可运行示例

1. 在指定表单中读取字段

页面可能有多个表单,每个表单中都存在相同的字段名称。先确定表单范围,再查找字段,可以避免误读其他表单中的同名控件。

<form id="profileForm">
  <label>
    用户名
    <input name="username" value="林安">
  </label>
  <button type="button" id="showProfile">读取</button>
</form>

<form id="searchForm">
  <input name="username" value="搜索关键词">
</form>

<p id="profileOutput"></p>

<script>
  $("#showProfile").on("click", function () {
    var value = $("#profileForm").find("[name='username']").val();
    $("#profileOutput").text(value);
  });
</script>

这里的选择范围是 #profileForm,因此不会读到 #searchForm 中的输入框。读取表单值使用 .val();显示普通文本时使用 .text(),而不是把值拼接进 HTML。

2. 在事件触发元素内部操作内容

当同一类组件在页面上重复出现时,可以从事件触发元素出发查找当前组件内部的目标,而不必使用全局选择器。

<div class="item">
  <span class="status">未完成</span>
  <button class="complete">完成</button>
</div>

<div class="item">
  <span class="status">未完成</span>
  <button class="complete">完成</button>
</div>

<script>
  $(".item").on("click", ".complete", function () {
    var item = $(this).closest(".item");
    item.find(".status").text("已完成");
  });
</script>

事件委托中的第二个参数 ".complete" 用来匹配触发事件的后代按钮;处理函数中的 this 是实际匹配到的按钮。closest(".item") 向上找到当前组件,随后 find(".status") 在该组件内部查找状态文本。这样不会把其他组件的状态一并改掉。

3. 检查有没有匹配元素

需要根据查找结果决定是否执行操作时,可以使用 .length 判断。空的 jQuery 对象并不会自动报错,但对它调用大多数 jQuery 方法也不会改变页面,因此显式判断能让意图更清楚。

var errorMessage = $("#loginForm").find(".error");

if (errorMessage.length > 0) {
  errorMessage.text("请检查输入内容");
} else {
  $("#loginForm").append(
    "<p class='error'>暂时没有错误提示</p>"
  );
}

示例中的 append() 接收的是开发者写定的 HTML 字符串。若内容来自用户输入,不要直接拼进 HTML;应优先使用 .text() 创建或设置文本,或先以安全方式构造 DOM。

4. 查找后代中的某一类元素再筛选

有时条件不适合全部写进选择器,或者已经拿到一组后代元素,可以继续使用 jQuery 的筛选方法。

var rows = $("#orderTable").find("tr");
var unpaidRows = rows.filter(function () {
  return $(this).attr("data-paid") === "false";
});

console.log("未付款行数:", unpaidRows.length);

find() 负责确定查找范围,filter() 则对已经找到的集合进一步筛选。要注意,filter() 的回调中 this 通常是当前 DOM 元素;在需要调用 jQuery 方法时再用 $(this) 包装即可。

五、动态内容与调用时机

find() 在调用时查找当时已经存在于 DOM 中的元素。它返回的是包含匹配元素的 jQuery 集合,不是一个会自动追踪未来变化的查询规则。因此,如果目标元素是在之后才插入的,之前保存的查找结果不会自动增加新元素。

var panel = $("#panel");
var buttons = panel.find(".action");

panel.append("<button class='action'>后来添加</button>");

console.log(buttons.length); // 仍是插入前的结果
console.log(panel.find(".action").length); // 重新查找后包含新按钮

若操作依赖新元素,通常在插入之后重新调用 find()。如果需要响应未来添加的元素,可以在一个稳定的祖先上使用事件委托,而不是在元素还不存在时只绑定直接事件。

$("#panel").on("click", ".action", function () {
  console.log("点击了操作按钮");
});

六、参数限制与选择器错误

find() 的常用形式是传入一个选择器字符串。它不是回调式的遍历方法,不能把函数当作选择条件;也不能把第二个参数当作查找上下文。下面这些写法并不是 find() 的标准用法:

// 不要把 find() 当作回调过滤器
$("#panel").find(function () {
  return true;
});

// find() 的常用接口只有一个选择器参数
$("#panel").find(".item", document);

需要按 JavaScript 条件筛选时,先用 find() 取得集合,再用 filter();需要限定查询根节点时,把范围作为 find() 前面的对象,例如 $("#panel").find(".item")。

选择器必须符合 jQuery 所支持的选择器语法。传入格式错误的选择器时,jQuery 可能抛出语法错误;不要把外部输入未经处理就拼成选择器。选择器能力还与 jQuery 版本有关:标准 CSS 选择器和 jQuery 扩展伪类并非同一套语法,某些扩展或浏览器支持情况可能因版本而异。跨版本代码应优先使用项目所需版本明确支持的选择器。

七、性能与多元素范围

如果调用对象中包含多个元素,find() 会在每个起点的后代中查找,结果是这些范围内符合条件的后代集合。若不同起点的范围相互重叠,同一个后代可能通过多个起点被找到;jQuery 通常会对结果进行去重并按文档顺序整理,但如果业务逻辑依赖唯一性,最好让查找范围足够明确,或自行检查结果。

var sections = $(".section");
var links = sections.find("a");

console.log("所有 section 范围内的链接数:", links.length);

日常页面中,先把查找限定在合理的容器内,通常比在整个文档中反复搜索更容易维护,也能减少无关匹配。对于极高频执行的操作,避免在循环里重复查找完全相同的静态范围;可以保存容器对象,或在适当时机缓存确实不会变化的结果。但如果 DOM 会变化,缓存的集合不会自动包含后来添加的元素,不能为了性能而忽略正确性。

var panel = $("#panel");

function updatePanel() {
  // 每次调用都重新查找,适用于内容可能变化的情况
  var actions = panel.find(".action");
  actions.addClass("ready");
}

八、安全注意事项:选择器不是 HTML 消毒器

find() 用来查询 DOM,不会把选择器字符串当作 HTML 插入页面,也不会因为查询本身执行脚本。因此,把 find() 简单说成“会造成 XSS”并不准确。不过,动态拼接未受信任内容仍有风险:特殊字符可能改变选择器的含义、造成选择器语法错误,或让代码选中非预期元素。查询结果随后若被用作删除、改写等操作,也可能带来业务层面的影响。

如果需要按动态 ID 查找,优先使用 jQuery 提供的 $.escapeSelector()(jQuery 3.0 及以上)来转义选择器中的特殊字符。以下代码适用于 ID 已存在于当前文档的情况:

var dynamicId = "user:profile";
var safeSelector = "#" + $.escapeSelector(dynamicId);
var element = $(document).find(safeSelector);

console.log(element.length);

如果项目使用的 jQuery 版本没有 $.escapeSelector(),不要自行编写一个未经验证的转义函数。可以改用 DOM API 按 ID 取元素,再包装为 jQuery 对象;如果目标仅是已找到元素的属性值,也可以先查找较大的安全范围,再用回调按字符串比较:

var dynamicId = "user:profile";
var element = $(document.getElementById(dynamicId));

var matched = $("#panel").find("[data-user-id]").filter(function () {
  return $(this).attr("data-user-id") === dynamicId;
});

查询与输出应分别考虑安全性:即使选择器构造正确,也不要把用户输入直接交给 .html() 或拼接进 HTML 字符串。显示纯文本用 .text();需要生成结构时,使用经过审查的 DOM 构造方式,并对确实需要展示的富文本进行适当清理。

九、常见错误排查

错误一:以为 find() 会匹配起点自身

下面的代码不会把 #panel 本身包含在结果中:

$("#panel").find("#panel");

判断起点自身是否匹配,用 is();需要把自身和后代都纳入某种处理时,应明确组合两类操作,而不是假设 find() 会包含自身。

错误二:传入了不正确的选择器

类选择器要以点号开头,ID 选择器要以井号开头;属性值含特殊字符时还要考虑正确引用和转义。若控制台出现选择器语法错误,先检查拼接后的完整选择器,而不是只检查变量来源。

var selector = ".item"; // 类选择器
var items = $("#list").find(selector);

console.log(selector);

错误三:查找范围选得太窄或太宽

范围太窄时,目标元素不在起点的后代中,结果自然为空;范围太宽时,可能修改到其他组件中的同名元素。可先检查起点对象数量和查找结果数量,再逐步确认 DOM 层级。

var scope = $("#dialog");
var targets = scope.find(".message");

console.log("范围元素数:", scope.length);
console.log("匹配元素数:", targets.length);

错误四:把 find() 返回值当成单个 DOM 元素

find() 返回 jQuery 集合,即使只匹配到一个元素,也不是原生 DOM 节点。可以调用 jQuery 方法,也可以通过索引取得 DOM 节点:

var results = $("#panel").find(".title");

results.text("新标题"); // jQuery 方法
var firstDomElement = results[0]; // 原生 DOM 节点,可能是 undefined
var firstJQueryElement = results.eq(0); // jQuery 对象

错误五:用旧结果期待自动包含新元素

已保存的集合不具备“未来查询”功能。动态添加节点后若需要处理它们,应重新查找,或对适合的场景采用事件委托。

十、find() 与常见方法的区别

方法主要用途典型示例
find()查找当前元素的后代$("#box").find(".item")
children()只查找直接子元素$("#box").children(".item")
closest()从当前元素开始向上查找最近的匹配祖先或自身$(this).closest(".item")
filter()筛选当前已有集合中的元素$(".item").filter(".active")
is()判断当前集合中是否有元素匹配条件$(this).is(".active")

尤其要区分 find() 与 children():前者会查找所有层级的后代,后者只看直接子元素。若页面结构多嵌套了一层,使用 children() 可能查不到,而 find() 仍能匹配。

总结

find() 的核心可以概括为:从当前 jQuery 集合出发,在其后代中查找符合选择器的元素,并返回新的 jQuery 集合。使用时重点检查三件事:查找范围是否正确、目标是不是起点的后代、选择器是否有效。

  • 用 $(范围).find("选择器") 做局部查询。
  • 它查找所有层级的后代,但不包含起点自身。
  • 需要判断自身用 is(),只查直接子元素用 children(),向上查找用 closest()。
  • 动态内容插入后,旧的查找结果不会自动更新;需要重新查找或使用事件委托。
  • 动态生成选择器时要处理特殊字符;选择器查询不能替代对 HTML 输出的安全处理。

把查找限制在明确的组件或容器中,并根据 DOM 关系选择合适的方法,通常能让 jQuery 代码更准确,也更容易维护。

© 版权声明

相关文章