☰
DOM 元素搜索指南:掌握 JavaScript 教程中的 getElement* 与 querySelector* 方法
2026/10/6 7:29:22 网站建设 项目流程
  • 文档/教程
  • 前端

【免费下载链接】en.javascript.info

Modern JavaScript Tutorial

项目地址:https://gitcode.com/gh_mirrors/en/en.javascript.info
点击查看免费下载

本文是 Modern JavaScript Tutorial(en.javascript.info)中 "Searching: getElement*, querySelector*" 章节的深度技术解析。文章围绕document.getElementById、querySelectorAll、querySelector、matches、closest与getElementsBy*六大搜索方法展开,并结合仓库内配套练习 1-find-elements/task.md 与真实页面 table.html 演示实战用法。读完本文,你将能根据id、CSS 选择器、标签名、类名或name属性精准定位任意 DOM 元素,并理解"活集合(live collection)"与"静态集合"的本质差异。

为什么需要"搜索"方法

在前一章 Walking the DOM(03-dom-navigation) 中我们了解到,DOM 允许我们通过childNodes、parentNode、nextSibling等导航属性在节点之间"行走"。但这种导航方式只在元素彼此相邻时高效:要拿到页面中任意一个元素,从document出发沿着导航属性一步步走过去既不现实也不可维护。

正如 browser environment(01-browser-environment) 所介绍的,document对象是页面的主要"入口点"。DOM 提供了另一组搜索方法(searching methods),让我们可以绕过导航属性,直接按特征(id、CSS 选择器、标签、类名、name)抓取任意元素。这就是本文的主题:getElement*与querySelector*两大家族。

document.getElementById:按 id 精准定位

如果一个元素带有id属性,无论它在文档中的哪个位置,都可以通过document.getElementById(id)拿到它:

<div id="elem"> <div id="elem-content">Element</div> </div> <script> // 获取元素 let elem = document.getElementById('elem'); // 将其背景设为红色 elem.style.background = 'red'; </script>

getElementById是定位单个元素最直接、性能最优的手段之一,在真实项目中它也是官方推荐的取元素方式。

名为 id 的全局变量

浏览器还提供了一种"快捷方式":文档中具有id的元素会同时生成一个同名的全局变量,直接引用该 DOM 元素:

<div id="elem"> <div id="elem-content">Element</div> </div> <script> // elem 直接引用了 id="elem" 的 DOM 元素 elem.style.background = 'red'; // id="elem-content" 含连字符,不能作为变量名 // ……但可以用方括号通过 window['elem-content'] 访问 </script>

不过,如果我们在 JavaScript 中声明了同名变量,它就会覆盖这个全局引用:

<div id="elem"></div> <script> let elem = 5; // 现在 elem 是 5,不再是 <div id="elem"> 的引用 alert(elem); // 5 </script>

不要在实战中使用"以 id 命名的全局变量"

该行为在 HTML 规范 中有描述,但主要是为了兼容旧代码。浏览器试图把 JS 命名空间和 DOM 命名空间混合起来"帮"我们,这对内联在 HTML 里的简单脚本没问题,但通常不是好做法:可能存在命名冲突;而且当读者只看 JS 代码、看不到 HTML 时,很难判断这个变量从何而来。

教程里为了简洁会直接用id引用元素,但真实项目中document.getElementById才是首选方法。

id必须是唯一的

一个文档中只能有一个元素拥有给定的id。如果出现多个相同id,使用它的方法行为将不可预测——例如document.getElementById可能随机返回其中任意一个。请务必遵守"id唯一"的规则。

只能在document上调用getElementById

该方法只能作用于document对象,它会在整个文档中查找给定的id。不存在anyElem.getElementById这种写法。

querySelectorAll:最强通用的 CSS 选择器搜索

elem.querySelectorAll(css)是用途最广的方法:返回elem内部所有匹配给定 CSS 选择器的元素。

例如,找出所有作为最后一个子元素的<li>:

<ul> <li>The</li> <li>test</li> </ul> <ul> <li>has</li> <li>passed</li> </ul> <script> let elements = document.querySelectorAll('ul > li:last-child'); for (let elem of elements) { alert(elem.innerHTML); // "test", "passed" } </script>

这个方法之所以强大,是因为任何 CSS 选择器都可以用:类型选择器、类选择器、属性选择器、后代组合、子组合、兄弟组合等一应俱全。

伪类同样支持

CSS 选择器中的伪类(如:hover、:active)也受支持。例如document.querySelectorAll(':hover')会返回当前指针悬停之上的元素集合(按嵌套顺序,从最外层的<html>到最内层)。

querySelector:只取第一个匹配项

elem.querySelector(css)返回给定 CSS 选择器的第一个匹配元素。

换句话说,它的结果等价于elem.querySelectorAll(css)[0],但后者会先找出全部匹配元素再取其一,而elem.querySelector只查找一个。因此它更快,写起来也更短。

在仓库配套练习的解法 solution.md 中,可以清晰看到这种替代关系:

// 5. 表单中的第一个 input form.getElementsByTagName('input')[0] // 或者 form.querySelector('input')

当只需要一个元素时,querySelector是比getElementsByTagName(...)[0]更简洁、更现代的选择。

matches:只判断、不搜索

前面几种方法都在"搜索" DOM,而elem.matches(css)不做任何查找,它只检查elem是否匹配给定的 CSS 选择器,返回true或false。

当我们遍历元素集合(例如数组或document.body.children)并想筛选出感兴趣的元素时,这个方法非常方便:

<a href="http://example.com/file.zip">...</a> <a href="http://ya.ru">...</a> <script> // 这里可以是任何集合,不限于 document.body.children for (let elem of document.body.children) { if (elem.matches('a[href$="zip"]')) { alert("The archive reference: " + elem.href); } } </script>

上例中a[href$="zip"]是属性选择器,$=表示"以……结尾",因此能精确筛出指向.zip压缩包的链接。matches常与事件委托配合使用(在e.target上判断点击来源),是 DOM 编程中的高频工具。

closest:向祖先链向上查找

元素的**祖先(ancestors)**包括:父元素、父元素的父元素,依此类推,最终连成从该元素到文档顶端的链条。

elem.closest(css)查找最近的、匹配给定 CSS 选择器的祖先。注意:elem自身也包含在查找范围内。

也就是说,closest从元素出发逐级向上检查每个父节点,一旦某级匹配选择器,搜索立即停止并返回该祖先:

<h1>Contents</h1> <div class="contents"> <ul class="book"> <li class="chapter">Chapter 1</li> <li class="chapter">Chapter 2</li> </ul> </div> <script> let chapter = document.querySelector('.chapter'); // LI alert(chapter.closest('.book')); // UL alert(chapter.closest('.contents')); // DIV alert(chapter.closest('h1')); // null(h1 不是祖先) </script>

closest是处理嵌套结构(如菜单、列表、卡片)中"点击了哪个容器"这类问题的利器,与事件委托配合可以大大简化代码。

getElementsBy*:按标签、类名、name 搜索

此外还有一组按标签、类名等查找节点的方法。如今它们大多属于"历史遗留",因为querySelector更强大且书写更短,这里讲解它们主要为了完整性——你仍会在旧脚本中见到它们:

  • elem.getElementsByTagName(tag)—— 按给定标签查找元素并返回集合;tag参数也可以是星号"*",表示"任意标签"。
  • elem.getElementsByClassName(className)—— 返回拥有给定 CSS 类的元素。
  • document.getElementsByName(name)—— 按name属性在整个文档范围内查找元素,极少使用。

基础用法:

// 获取文档中所有 div let divs = document.getElementsByTagName('div');

在指定元素内部继续搜索也同样自然。下面示例查找表格中的所有input标签:

<table id="table"> <tr> <td>Your age:</td> <td> <label> <input type="radio" name="age" value="young" checked> less than 18 </label> <label> <input type="radio" name="age" value="mature"> from 18 to 50 </label> <label> <input type="radio" name="age" value="senior"> more than 60 </label> </td> </tr> </table> <script> let inputs = table.getElementsByTagName('input'); for (let input of inputs) { alert( input.value + ': ' + input.checked ); } </script>

常见坑一:别忘字母 "s"!

新手常把getElement**s**ByTagName写成getElementByTagName。规律如下:

  • getElementById中没有"s",因为它只返回单个元素;
  • getElementsByTagName返回元素集合,所以里面有"s"。

常见坑二:返回的是集合,不是元素!

另一个普遍错误是试图直接给集合赋值:

// 不生效 document.getElementsByTagName('input').value = 5;

这样写不会生效,因为拿到的是一组 input 的集合,赋值被施加在集合本身而非集合内的元素上。正确做法是遍历集合,或先按下标取出元素再赋值:

// 正确(假设存在 input) document.getElementsByTagName('input')[0].value = 5;

按 name 与按 class 的组合示例

下面的例子同时演示了getElementsByName(文档级)与getElementsByClassName(元素级):

<form name="my-form"> <div class="article">Article</div> <div class="long article">Long article</div> </form> <script> // 按 name 属性查找 let form = document.getElementsByName('my-form')[0]; // 在 form 内部按 class 查找 let articles = form.getElementsByClassName('article'); alert(articles.length); // 2,找到两个 class 含 "article" 的元素 </script>

活集合(Live collections)与静态集合

所有getElementsBy*方法返回的都是活集合(live collection):这类集合始终反映文档的当前状态,当文档变化时会"自动更新"。

下面例子中有两段脚本:

  1. 第一段创建了对<div>集合的引用,此时其长度为1;
  2. 浏览器解析到又一个<div>后运行的第二段脚本看到长度为2。
<div>First div</div> <script> let divs = document.getElementsByTagName('div'); alert(divs.length); // 1 </script> <div>Second div</div> <script> alert(divs.length); // 2 </script>

与之相反,querySelectorAll返回静态集合(static collection),它就像元素的一个固定数组。若换用它,两段脚本输出的都是1:

<div>First div</div> <script> let divs = document.querySelectorAll('div'); alert(divs.length); // 1 </script> <div>Second div</div> <script> alert(divs.length); // 1 </script>

现在差异一目了然:文档中出现新的div后,静态集合并没有随之增长。这一特性在动态页面中尤为关键——如果你先取得集合、之后 DOM 又发生变化,getElementsBy*的活集合会立即反映新增/删除的节点,而querySelectorAll的快照则保持不变。

实战演练:查找表格与表单中的元素

仓库为本章配有一道完整练习 1-find-elements/task.md,其页面 table.html 同时包含表单与表格结构。练习要求完成六项查找:

  1. id="age-table"的表格;
  2. 该表格内所有label元素(共 3 个);
  3. 表格内第一个td(含 "Age" 字样);
  4. name="search"的表单;
  5. 该表单中的第一个input;
  6. 该表单中的最后一个input。

官方解法 solution.md 展示了每种目标的多条可行路径,恰好覆盖了本文全部方法:

// 1. id="age-table" 的表格 let table = document.getElementById('age-table') // 2. 表格内所有 label 元素 table.getElementsByTagName('label') // 或 document.querySelectorAll('#age-table label') // 3. 表格内第一个 td(含 "Age" 字样) table.rows[0].cells[0] // 或 table.getElementsByTagName('td')[0] // 或 table.querySelector('td') // 4. name="search" 的表单 // 假设文档中只有一个 name="search" 的元素 let form = document.getElementsByName('search')[0] // 或,专门针对表单 document.querySelector('form[name="search"]') // 5. 表单中的第一个 input form.getElementsByTagName('input')[0] // 或 form.querySelector('input') // 6. 表单中的最后一个 input let inputs = form.querySelectorAll('input') // 找到全部 input inputs[inputs.length - 1] // 取最后一个

注意第 3 问中table.rows[0].cells[0]用到了表格特有的rows/cells集合属性,这是getElementsBy*之外的另一种快捷路径。可见,同一查找目标往往存在多种等价实现,理解每种方法的特性(是否活集合、是否支持复杂选择器、调用对象限制)才能选出最合适的方案。

总结

DOM 中搜索节点共有6 个主要方法:

方法按什么搜索能否在元素上调用是否活集合
querySelectorCSS 选择器✔-
querySelectorAllCSS 选择器✔-
getElementByIdid--
getElementsByNamename-✔
getElementsByTagName标签或'*'✔✔
getElementsByClassNameclass✔✔

使用频率最高的是querySelector与querySelectorAll,但getElement(s)By*在特定场景仍有用武之地,也常见于旧脚本。

除此之外还有两个高频辅助方法:

  • elem.matches(css)—— 检查elem是否匹配给定 CSS 选择器;
  • elem.closest(css)—— 查找最近的、匹配给定 CSS 选择器的祖先,elem自身也会被检查。

最后再补充一个用于判断父子关系的方法(有时很实用):

  • elemA.contains(elemB)—— 若elemB在elemA内部(是elemA的后代),或elemA === elemB,返回true。

至此,从getElementById的单点精准定位,到querySelectorAll的任意 CSS 选择器批量抓取,再到matches/closest的关系判断,你已经掌握了在 document 章节(2-ui/1-document) 后续内容中操作页面元素的全部"定位武器"。下一章 basic-dom-node-properties(05-basic-dom-node-properties) 将进一步介绍这些元素节点自身的属性体系。

  • 文档/教程
  • 前端

【免费下载链接】en.javascript.info

Modern JavaScript Tutorial

项目地址:https://gitcode.com/gh_mirrors/en/en.javascript.info
点击查看免费下载
上一篇:AstroWind社区贡献:如何参与开源项目开发
下一篇:GLM-4-9B-Chat性能优化技巧:10个提升推理速度的方法

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询