正在加载...

选取元素

面包架上有一个标题和三张纸条。标题写着 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 上,不在元素上。

一个 id

javascript
let loaf = document.getElementById("loaf");
console.log(loaf.textContent);
console.log(loaf === null);

第一行是 Rye。第二行是 false,因为标题就在架子上。就算两个元素共用 id loaf,这次调用仍然只返回文档里的第一个。

class 名和标签名

两次调用都交还活的 HTMLCollection。先读 length,再取一张纸条。计数用只有四个元素的架子,不用读出文件。

class 和标签

javascript
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。

第一处匹配

javascript
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。

全部匹配

javascript
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。

什么都没对上

javascript
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,所以不算进那三张。

页面示例 — 三张纸条

html
<!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。

核对架子

  1. 记下标题文字,期望 Rye,再核对 null,期望 false
  2. 记下 class 长度、p 长度和 sold 长度:3、3、1
  3. 记下第一个 .tag 的文字,期望 Morning,再记 #shelf .sold,期望 Evening
  4. 记下 querySelectorAll 的长度,期望 3,再记下标 1,期望 Noon
  5. 记下缺失的 id 和缺失的 querySelector,两次都期望 null
  6. 记下 querySelectorAll(".oven").length,期望 0
  7. 读段落,期望 3 / Morning / Evening

叫错了

页面仍然开着。你写的那次调用要的是别的东西。

  • 把 .tag 传给 getElementsByClassName;点只属于 CSS 选择器
  • 把不带点的 tag 传给 querySelector,却指望拿到纸条
  • 把下标 1 当成第一张纸条
  • 把 querySelectorAll 的落空当成 null,其实长度是 0
  • 把 getElementById 的落空当成长度为 0 的列表
  • 在读出文件上数 getElementsByTagName("p"),却期望 3
  • 在 HTMLCollection 上调用 .map;它不是数组
  • 在这一页读 parentElement;那是树那一页的事

带走这些

  • getElementById 交还一个元素,或 null
  • getElementsByClassName 和 getElementsByTagName 交还活的 HTMLCollection
  • 按 class 找的方法要 tag,不要 .tag
  • querySelector 交还第一处 CSS 匹配,或 null
  • querySelectorAll 交还静态 NodeList;落空时长度是 0
  • 下标 0 是 Morning,下标 1 是 Noon
  • 下一页会改你已经选取的元素的 HTML

🧠 测试您的知识

准备开始

测试您的知识

通过这个互动测验挑战自己,看看你对这个主题的理解程度如何

❓
8
问题
🎯
70%
及格要求
♾️
∞
时间
🔄
∞
尝试次数

📝 说明

  • 仔细阅读每个问题
  • 为每个问题选择最佳答案
  • 您可以随时重新参加测验
  • 您的进度将显示在顶部