选取元素
面包架上有一个标题和三张纸条。标题写着 Rye。纸条写班次:Morning、Noon、Evening。最后一张还带着 class sold。架子本身是 id 为 shelf 的 main。里面是 id 为 loaf 的 h2,接着三个 class 为 tag 的 p。选取,就是用你定的名字向活文档要这些节点。document.getElementById("loaf") 返回标题,文字是 Rye。document.getElementsByClassName("tag") 返回长度为 3 的活列表。document.querySelector(".tag") 返回第一张纸条 Morning。document.querySelectorAll(".tag") 返回一份静态列表,下标 1 是 Noon。架子上从没写过的名字,从 querySelector 得到 null,从 querySelectorAll 得到长度为 0 的列表。
五次调用,不是沿着树往下走
DOM 那一页说出标题的父元素,并把元素子节点和全部节点对照着数。这一页不读 parentElement、nextElementSibling 和 children,也不调用 Math。树已经在。这里要分清哪次调用交还一个节点,哪次交还列表,哪种结果表示什么都没对上。
每次调用交还什么
在只有标题和三张纸条的架子上数。下面的读出文件多了一个段落,所以那里 p 的个数会变。
📊 每次调用交还什么
| 调用 | 交还什么 | 在这个架子上 | 容易混 |
|---|---|---|---|
getElementById("loaf") |
一个元素,或 null |
标题文字 Rye | 还得按下标去读的列表 |
getElementsByClassName("tag") |
活的 HTMLCollection |
长度 3 | 写上点,比如 .tag |
getElementsByTagName("p") |
活的 HTMLCollection |
长度 3 | 标题本身,它是 h2 |
querySelector(".tag") |
第一处匹配,或 null |
纸条 Morning | 每一张纸条 |
querySelectorAll(".tag") |
静态 NodeList |
长度 3;下标 1 是 Noon | 一份活集合 |
querySelectorAll(".oven") |
空的 NodeList |
长度 0 | null |
按 class 找的方法和 CSS 选择器,点的写法不一样。getElementsByClassName("tag") 要的是不带点的名字 tag。getElementsByClassName(".tag") 去找名字真的叫 .tag 的 class,长度是 0。querySelector 要 CSS,所以点留在 .tag 上。querySelector("tag") 找标签名是 tag 的元素,一个也没有,返回 null。下标 0 是第一张纸条。下标 1 是 Noon。getElementsByClassName 的列表是活的:后面的页面再添一张 tag 纸条,长度会变大。querySelectorAll 保持调用那一刻的长度。Evening 有两个 class,tag 和 sold,所以它既在长度为 3 的列表里,也是 sold 的唯一匹配。
一个 id,一个元素
id 在页面上应当唯一。getElementById 交还那一个元素;没有这个 id 就是 null。它不交还列表,而且只在 document 上,不在元素上。
let loaf = document.getElementById("loaf");
console.log(loaf.textContent);
console.log(loaf === null);
第一行是 Rye。第二行是 false,因为标题就在架子上。就算两个元素共用 id loaf,这次调用仍然只返回文档里的第一个。
class 名和标签名
两次调用都交还活的 HTMLCollection。先读 length,再取一张纸条。计数用只有四个元素的架子,不用读出文件。
console.log(document.getElementsByClassName("tag").length);
console.log(document.getElementsByTagName("p").length);
console.log(document.getElementsByClassName("sold").length);
三行是 3、3、1。三张纸条共用 tag。三个都是 p,标题是 h2,所以在这个架子上,按标签数和按 class 数一样。只有 Evening 有 sold。getElementsByClassName(".tag") 是另一次调用:点不属于 class 名,所以那个长度是 0。
第一处 CSS 匹配
querySelector 交还一个元素,按文档顺序的第一个,否则是 null。
console.log(document.querySelector(".tag").textContent);
console.log(document.querySelector("#shelf .sold").textContent);
第一行是 Morning。第二行是 Evening。#shelf .sold 的意思是架子里面带 class sold 的元素,不是架子自己。document.getElementById("shelf").querySelector(".sold") 从架子开始找,落到同一张 Evening 纸条。
每一处匹配,再取下标
querySelectorAll 把每一处匹配放进静态的 NodeList。列表可以是空的。它不是 null。
let tags = document.querySelectorAll(".tag");
console.log(tags.length);
console.log(tags[1].textContent);
长度是 3。下标 1 是 Noon。下标 0 是 Morning,下标 2 是 Evening。后面的脚本再添纸条,这份列表不会变长。getElementsByClassName("tag") 得到的 HTMLCollection 会变长。一个是当时的快照,另一个一直是活的。
架子上没写过的名字
去要文件里没有的 id 和 class。
console.log(document.getElementById("oven"));
console.log(document.querySelector(".oven"));
console.log(document.querySelectorAll(".oven").length);
第一行是 null。第二行是 null。第三行是 0。什么都没对上时,querySelectorAll 仍然交还列表,所以读到的长度是 0,列表本身不是 null。getElementById 没有列表可交,落空就是 null,不是 0。
页面上的一行
一个段落报出有几张 tag 纸条、第一张是什么、sold 那张是什么。脚本放在 body 末尾,等这些元素已经在。这一行没有 class tag,所以不算进那三张。
<!DOCTYPE html>
<html>
<head>
<title>selecting — page</title>
</head>
<body>
<main id="shelf">
<h2 id="loaf">Rye</h2>
<p class="tag">Morning</p>
<p class="tag">Noon</p>
<p class="tag sold">Evening</p>
<p id="line">…</p>
</main>
<script>
let tags = document.querySelectorAll(".tag");
let line = document.getElementById("line");
line.textContent = tags.length + " / " + tags[0].textContent + " / " + document.querySelector(".sold").textContent;
</script>
</body>
</html>
段落写成 3 / Morning / Evening。在这个文件里,getElementsByTagName("p") 数到 4,因为这一行又是一个 p。querySelectorAll(".tag") 仍然是 3。下一页会改这些调用已经找到的元素的 HTML。
核对架子
- 记下标题文字,期望 Rye,再核对 null,期望 false
- 记下 class 长度、
p长度和 sold 长度:3、3、1 - 记下第一个
.tag的文字,期望 Morning,再记#shelf .sold,期望 Evening - 记下
querySelectorAll的长度,期望 3,再记下标 1,期望 Noon - 记下缺失的 id 和缺失的
querySelector,两次都期望 null - 记下
querySelectorAll(".oven").length,期望 0 - 读段落,期望 3 / Morning / Evening
叫错了
页面仍然开着。你写的那次调用要的是别的东西。
- 把
.tag传给getElementsByClassName;点只属于 CSS 选择器 - 把不带点的
tag传给querySelector,却指望拿到纸条 - 把下标 1 当成第一张纸条
- 把
querySelectorAll的落空当成null,其实长度是 0 - 把
getElementById的落空当成长度为 0 的列表 - 在读出文件上数
getElementsByTagName("p"),却期望 3 - 在
HTMLCollection上调用.map;它不是数组 - 在这一页读
parentElement;那是树那一页的事
带走这些
getElementById交还一个元素,或nullgetElementsByClassName和getElementsByTagName交还活的HTMLCollection- 按 class 找的方法要
tag,不要.tag querySelector交还第一处 CSS 匹配,或nullquerySelectorAll交还静态NodeList;落空时长度是 0- 下标 0 是 Morning,下标 1 是 Noon
- 下一页会改你已经选取的元素的 HTML
🧠 测试您的知识
测试您的知识
通过这个互动测验挑战自己,看看你对这个主题的理解程度如何
📝 说明
- 仔细阅读每个问题
- 为每个问题选择最佳答案
- 您可以随时重新参加测验
- 您的进度将显示在顶部