DOM 节点:网页结构的核心单元
在前端开发中,DOM(Document Object Model,文档对象模型) 是浏览器将 HTML/XML 文档解析后形成的 "树形结构",而 DOM 节点(Node) 则是这棵树的基本组成单元 ------ 每个 HTML 标签、文本、注释甚至属性,都对应一个 DOM 节点。理解 DOM 节点是操作网页(如修改内容、样式、结构)的基础。
一、DOM 节点的本质与作用
浏览器加载 HTML 后,会将代码 "翻译" 成一个 DOM 树:
- 树根是
document
(代表整个文档); - 树干 / 树枝是 HTML 标签(如
<html>
、<body>
、<div>
); - 树叶可能是文本(如
<p>
里的文字)、注释或属性。
我们通过 JavaScript 操作 DOM 节点,就能实现网页的 "动态交互"------ 比如点击按钮修改文本、添加新元素、删除广告等,本质都是在操作 DOM 节点。
二、DOM 节点的 5 种核心类型
不同的 HTML 内容对应不同类型的节点,每种节点有专属的属性和方法,最常用的是前 4 种:
节点类型 | 描述 | 示例(对应 HTML 代码) | 核心特征 |
---|---|---|---|
元素节点(Element) | 最核心的节点类型,对应 HTML 标签(如 <div> 、<p> 、<button> ) |
<div class="box">Hello</div> 中的 <div> |
可通过 tagName 获取标签名(如 DIV ) |
文本节点(Text) | 对应标签内的文本内容(不包含标签本身) | 上述 <div> 中的 "Hello" |
内容通过 nodeValue 属性获取 / 修改 |
属性节点(Attr) | 对应 HTML 标签的属性(如 class 、id 、src ) |
上述 <div> 的 class="box" |
通常通过元素节点的 attributes 访问 |
注释节点(Comment) | 对应 HTML 中的注释(<!-- 注释内容 --> ) |
<!-- 这是一个盒子 --> |
nodeValue 为注释文本,不显示在页面 |
文档节点(Document) | 代表整个 HTML 文档(DOM 树的根),所有其他节点都是它的 "后代" | 全局对象 document 就是文档节点 |
提供创建 / 查找节点的方法(如 getElementById ) |
三、DOM 节点的核心属性(通用 + 专属)
所有 DOM 节点都继承自 Node
接口,拥有一些通用属性;不同类型的节点还有专属属性。
1. 所有节点通用的核心属性
属性名 | 作用 |
---|---|
nodeType |
节点类型(用数字表示):1 = 元素节点、3 = 文本节点、8 = 注释节点、9 = 文档节点 |
nodeName |
节点名称:元素节点是标签名(大写,如 DIV )、文本节点是 #text 、注释节点是 #comment |
nodeValue |
节点值:文本节点是文本内容、注释节点是注释内容、元素节点为 null |
parentNode |
获取当前节点的 "父节点"(每个节点只有一个父节点,document 没有父节点) |
childNodes |
获取当前节点的 "所有子节点"(返回 NodeList 类数组,包含文本、注释等) |
previousSibling /nextSibling |
获取当前节点的 "前一个兄弟节点"/"后一个兄弟节点"(可能包含空白文本节点) |
2. 元素节点(Element)的专属属性
元素节点是最常用的节点类型,除了通用属性,还有专门操作标签的属性:
属性名 | 作用 | 示例 |
---|---|---|
tagName |
获取元素标签名(大写,与 nodeName 一致,但更直观) |
document.querySelector('div').tagName → DIV |
id |
获取 / 设置元素的 id 属性 |
div.id = "new-id" |
className |
获取 / 设置元素的 class 属性(因 class 是 JS 关键字,故用 className ) |
div.className = "box red" |
classList |
操作元素的 class (更灵活,支持添加、删除、判断) |
div.classList.add("active") (添加类) |
attributes |
获取元素的 "所有属性节点"(返回 NamedNodeMap 类数组) |
div.attributes → 包含 class 、id 等属性 |
innerHTML |
获取 / 设置元素的 "内部 HTML 内容"(可解析标签) | div.innerHTML = "<p>新内容</p>" |
textContent |
获取 / 设置元素的 "内部文本内容"(不解析标签,只保留文本) | div.textContent = "新文本" |
四、DOM 节点的核心操作(增删改查)
前端开发中,对 DOM 节点的操作主要围绕 "查找、创建、修改、删除、插入" 展开,核心方法如下:
1. 查找节点(获取已有节点)
通过 document
或父元素调用方法,找到目标节点(最常用前 3 种):
方法名 | 作用 | 示例 |
---|---|---|
getElementById(id) |
通过 id 查找元素节点(唯一,返回单个节点) |
document.getElementById("box") |
getElementsByClassName(class) |
通过 class 查找元素节点(返回 HTMLCollection 类数组) |
document.getElementsByClassName("red") |
getElementsByTagName(tag) |
通过标签名查找元素节点(返回 HTMLCollection 类数组) |
document.getElementsByTagName("div") |
querySelector(selector) |
通过 CSS 选择器查找元素节点(返回第一个匹配节点) | document.querySelector(".box #title") |
querySelectorAll(selector) |
通过 CSS 选择器查找所有匹配节点(返回 NodeList 类数组) |
document.querySelectorAll("p.active") |
parentNode.children |
获取父元素的 "所有子元素节点"(只含元素节点,不含文本 / 注释,常用) | div.children → 所有子 <div> /<p> 等 |
2. 创建节点
当需要添加新内容时,先创建节点,再插入到 DOM 树中:
方法名 | 作用 | 示例 |
---|---|---|
createElement(tag) |
创建元素节点(如 <div> 、<button> ) |
const newDiv = document.createElement("div") |
createTextNode(text) |
创建文本节点 | const textNode = document.createTextNode("Hello") |
createComment(comment) |
创建注释节点 | const commentNode = document.createComment("新注释") |
3. 插入节点
创建节点后,需通过 "父节点" 将其插入到 DOM 树中(否则节点只存在于内存,不显示在页面):
方法名 | 作用 | 示例(parent 是父元素,newNode 是新节点,refNode 是参考节点) |
---|---|---|
parent.appendChild(newNode) |
将新节点插入到父节点的 "最后一个子节点" 后面 | document.body.appendChild(newDiv) |
parent.insertBefore(newNode, refNode) |
将新节点插入到 "参考节点 refNode" 的前面 | div.insertBefore(newP, div.firstChild) |
4. 修改节点
修改已存在的节点(内容、属性、样式等):
- 修改内容 :用
innerHTML
(含标签)或textContent
(纯文本)
示例:document.querySelector("p").textContent = "修改后的文本"
- 修改属性 :直接赋值(如
img.src = "new.jpg"
)或用setAttribute
示例:div.setAttribute("class", "new-box")
(设置属性)、div.removeAttribute("id")
(删除属性) - 修改样式 :通过
style
属性操作行内样式(注意 CSS 属性转驼峰,如backgroundColor
)
示例:div.style.color = "red"
、div.style.fontSize = "16px"
5. 删除节点
通过 "父节点" 删除子节点(不能直接删除自己):
方法名 | 作用 | 示例(parent 是父元素,child 是要删除的子节点) |
---|---|---|
parent.removeChild(child) |
删除父节点下的指定子节点 | document.body.removeChild(newDiv) |
child.remove() |
(ES6+)直接删除节点(无需通过父节点,更简洁) | newDiv.remove() |
五、常见误区与注意点
-
空白文本节点问题 :HTML 中的换行、空格会被解析为 "文本节点",导致
childNodes
可能包含空白节点。示例:
<div>\n <p>Hello</p>\n</div>
中,div.childNodes
包含 "换行空格" 文本节点、<p>
元素节点、"换行空格" 文本节点。解决:若只需元素节点,用
children
代替childNodes
。 -
nodeList
与HTMLCollection
的区别:- 两者都是 "类数组"(需用
Array.from()
转成真正数组才能用map
/filter
); nodeList
(如querySelectorAll
返回)包含所有类型节点(元素、文本、注释),HTMLCollection
(如getElementsByClassName
返回)只含元素节点;HTMLCollection
是 "动态的"(文档变化时自动更新),nodeList
是 "静态的"(文档变化不影响)。
- 两者都是 "类数组"(需用
-
innerHTML
的安全风险 :若innerHTML
赋值的内容来自用户输入(如评论、表单),可能存在 XSS 攻击 (注入恶意脚本)。解决:纯文本用
textContent
,需解析标签时先过滤恶意代码。
六、实际应用场景示例
通过一个简单案例,串联 DOM 节点的 "查、创、插、改、删" 操作:
html
<!-- HTML 结构 -->
<div id="container">
<p class="title">原标题</p>
</div>
<button id="addBtn">添加内容</button>
<button id="delBtn">删除内容</button>
<script>
// 1. 查找节点
const container = document.getElementById("container");
const addBtn = document.getElementById("addBtn");
const delBtn = document.getElementById("delBtn");
// 2. 点击"添加"按钮:创建并插入节点
addBtn.onclick = function() {
// 创建元素节点和文本节点
const newP = document.createElement("p");
const newText = document.createTextNode("新添加的文本");
// 组装节点(将文本节点插入到 p 中)
newP.appendChild(newText);
// 设置 p 的样式和属性
newP.style.color = "blue";
newP.className = "content";
// 将 p 插入到 container 中(最后一个子节点后面)
container.appendChild(newP);
// 同时修改原标题的内容
document.querySelector(".title").textContent = "修改后的标题";
};
// 3. 点击"删除"按钮:删除最后一个子节点
delBtn.onclick = function() {
const lastChild = container.lastElementChild; // 只找元素节点
if (lastChild) { // 确保有子节点可删
container.removeChild(lastChild);
}
};
</script>
总结
DOM 节点是网页的 "骨架",所有前端动态交互都基于对节点的操作。核心要点:
- 明确 5 种节点类型,重点掌握元素节点 和文本节点;
- 熟记通用属性(
nodeType
、parentNode
)和元素节点专属属性(className
、innerHTML
); - 掌握 "查、创、插、改、删"5 类核心操作,结合实际场景灵活运用;
- 注意空白文本节点、类数组转换、XSS 安全等细节问题。