DOM 导航
使用 JavaScript 导航 HTML DOM
Section titled “使用 JavaScript 导航 HTML DOM”HTML 文档对象模型 (DOM) 将 HTML 文档表示为节点构成的树状结构。JavaScript 允许你导航这个树,访问并操作其中的元素、属性和内容。
理解 DOM 节点
Section titled “理解 DOM 节点”根据 W3C HTML DOM 标准,HTML 文档中的一切都是节点:
- 整个文档是一个文档节点(
document)。 - 每个 HTML 元素(例如,
<h1>、<p>、<div>)是一个元素节点。 - HTML 元素内部的实际文本内容是文本节点。
- 每个 HTML 属性(例如,
<a>中的href,<img>中的src)是一个属性节点(尽管通常通过元素属性访问)。 - 注释(
<!-- ... -->)是注释节点。
想象一个 HTML 文档是一棵家谱树。<html> 元素是根。像 <head> 和 <body> 这样的元素是它的子代。嵌套更深的元素是后代。这种树状结构允许 JavaScript 遍历并与文档的任何部分进行交互。
通过 HTML DOM,JavaScript 可以:
- 查找、获取、改变、添加或删除 HTML 元素。
- 改变 HTML 属性。
- 改变 CSS 样式。
- 响应 HTML 事件。
DOM 树中的节点具有层级关系:
- 根节点:树中最顶层的节点(通常是 HTML 文档中的
<html>元素,或document节点本身)。 - 父节点:每个节点(根节点除外)都有且只有一个父节点。
- 子节点:一个节点可以有零个、一个或多个子节点。
- 同级节点:共享同一个父节点的节点是同级节点。
- 后代节点:一个节点的子节点、子节点的子节点,依此类推。
- 祖先节点:一个节点的父节点、父节点的父节点,依此类推,直到根节点。
考虑这个简单的 HTML 结构:
<html> <head> <title>DOM Tutorial</title> </head> <body> <h1>DOM Lesson One</h1> <p>Hello world!</p> </body></html>从此结构中可知:
<html>是根元素节点。<html>是<head>和<body>的父节点。<head>和<body>是<html>的同级节点和子节点。<title>是<head>的子节点。- 文本 “DOM Tutorial” 是一个文本节点,也是
<title>的子节点。 <h1>和<p>是<body>的子节点,也是同级节点。
节点间的导航
Section titled “节点间的导航”JavaScript 提供了基于这些关系来导航 DOM 树的属性:
包含空白/文本/注释节点的属性:
Section titled “包含空白/文本/注释节点的属性:”parentNode:访问当前节点的父节点。childNodes:返回一个NodeList(集合),包含所有子节点,包括文本节点(空白)和注释节点。firstChild:返回第一个子节点(可以是文本、注释或元素节点)。lastChild:返回最后一个子节点(可以是文本、注释或元素节点)。nextSibling:返回树中同一层级的下一个节点(可以是文本、注释或元素节点)。previousSibling:返回树中同一层级的上一个节点(可以是文本、注释或元素节点)。
专注于元素节点的属性(通常更方便):
Section titled “专注于元素节点的属性(通常更方便):”parentElement:类似于parentNode,但如果父节点不是元素节点,则返回null。children:返回一个HTMLCollection,只包含子元素节点(忽略文本节点和注释节点)。firstElementChild:返回第一个子元素节点。lastElementChild:返回最后一个子元素节点。nextElementSibling:返回下一个元素同级节点。previousElementSibling:返回上一个元素同级节点。
常见陷阱:childNodes、firstChild、lastChild、nextSibling 和 previousSibling 可能会返回文本节点(通常只是 HTML 源代码中元素之间的空白)或注释节点。如果你特别需要元素节点,请使用它们的 Element 对应属性,如 children、firstElementChild 等。这可以帮助你避免意外的错误或行为。 |
|---|
访问节点内容:textContent 和 innerHTML
Section titled “访问节点内容:textContent 和 innerHTML”一个常见的错误是期望元素节点(例如,<p>我的文本</p>)直接包含其文本。元素节点 <p> 实际上包含一个文本节点,其值是 “My Text”。
要获取或设置元素及其后代的文本内容:
textContent:获取或设置一个节点及其后代的文本内容。对于处理文本而言,它通常更安全且更快,因为它不会解析 HTML。innerHTML:获取或设置元素内包含的 HTML 标记。从不可信来源设置内容时请谨慎使用,因为存在潜在的 XSS 安全风险。它会重新解析内容,这可能会比较慢。
nodeValue 属性可用于获取或设置某些节点类型的值,主要是文本节点和注释节点。对于元素节点,nodeValue 为 null。
使用 firstElementChild 和 textContent 的示例:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>DOM Navigation Example</title></head><body> <div id="container"> <h1>My First Page</h1> <p id="intro">This is the introduction.</p> </div> <p id="demo">Result will appear here.</p>
<script> const containerDiv = document.getElementById("container"); const firstHeading = containerDiv.firstElementChild; // 获取 <h1>
const demoP = document.getElementById("demo"); if (firstHeading && demoP) { // 使用 textContent 从 h1 获取文本 demoP.textContent = "The first element's text: " + firstHeading.textContent; }
// 使用 childNodes 和 nodeValue 从 p#intro 获取文本(更详细) // const introP = document.getElementById("intro"); // if (introP && introP.firstChild && introP.firstChild.nodeType === Node.TEXT_NODE) { // console.log("Intro 文本节点的值:", introP.firstChild.nodeValue); // } </script></body></html>在此示例中,document.getElementById() 是一个用于查找元素的方法。firstElementChild 和 textContent 是属性。
DOM 根节点
Section titled “DOM 根节点”JavaScript 提供对文档关键部分的直接访问:
document.documentElement:表示文档的根元素(通常是<html>标签)。document.body:表示文档的<body>元素。document.head:表示文档的<head>元素。
示例:弹窗显示 body 的 HTML 内容。
/*// 这将在一个弹窗中显示 body 的整个 HTML 内容。// 弹窗显示大量 HTML 时请谨慎,因为它可能难以阅读。
if (document.body) { alert(document.body.innerHTML);} else { // 如果脚本在 body 解析之前运行且未使用 defer/DOMContentLoaded,可能会发生这种情况 console.error("document.body 尚未准备好。");}*/nodeName 属性
Section titled “nodeName 属性”只读属性 nodeName 指定了节点的名称:
- 对于元素节点,它是大写的标签名(例如,“DIV”、“P”、“H1”)。
- 对于属性节点,它是属性名。
- 对于文本节点,它总是 “#text”。
- 对于注释节点,它总是 “#comment”。
- 对于文档节点,它总是 “#document”。
const myDiv = document.createElement('div');console.log(myDiv.nodeName); // 输出: "DIV"nodeType 属性
Section titled “nodeType 属性”只读属性 nodeType 返回一个数字,代表节点的类型。这对于检查你正在处理的节点类型非常有用。
关键的 nodeType 值:
| 节点类型描述 | NodeType 值 | 常量 (例如,Node.ELEMENT_NODE) |
|---|---|---|
| 元素 | 1 | Node.ELEMENT_NODE |
| 属性 | 2 | Node.ATTRIBUTE_NODE |
| 文本 | 3 | Node.TEXT_NODE |
| 注释 | 8 | Node.COMMENT_NODE |
| 文档 | 9 | Node.DOCUMENT_NODE |
| 文档片段 | 11 | Node.DOCUMENT_FRAGMENT_NODE |
const pElement = document.querySelector('p');if (pElement && pElement.firstChild && pElement.firstChild.nodeType === Node.TEXT_NODE) { // 如果 pElement 存在,并且它的第一个子节点存在且其类型为 Node.TEXT_NODE console.log("第一个子节点是文本节点。");} else if (pElement && pElement.firstChild && pElement.firstChild.nodeType === Node.ELEMENT_NODE) { // 否则,如果 pElement 存在,并且它的第一个子节点存在且其类型为 Node.ELEMENT_NODE console.log("第一个子节点是元素节点。");}