JavaScript HTML DOM 节点列表(长文解析)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
在现代 Web 开发中,JavaScript 与 HTML DOM 的交互是实现动态页面效果的核心能力之一。而 JavaScript HTML DOM 节点列表作为连接两者的关键桥梁,为开发者提供了操作页面元素的高效工具。无论是构建响应式表单、动态更新内容,还是实现复杂的交互逻辑,节点列表都是不可或缺的工具。本文将从基础概念出发,逐步深入讲解节点列表的原理、操作方法及实际应用,帮助开发者快速掌握这一技术。
一、DOM 基础概念:理解节点的层级结构
1.1 DOM 的本质:一棵动态的“树”
HTML 文档在浏览器中会被解析为一个由节点(Node)组成的树状结构,称为 Document Object Model(DOM)。每个 HTML 元素、属性、文本甚至注释都是 DOM 树中的一个节点。例如,<div>
是元素节点,class="container"
是属性节点,而文本内容则是文本节点。
比喻:可以将 DOM 想象成一座图书馆的目录系统。根节点 <html>
是图书馆的大门,每个子节点(如 <head>
和 <body>
)是不同楼层,而 <div>
、<p>
等元素则是书架上的书籍。开发者通过 JavaScript 操作 DOM,就像在图书馆中快速检索和调整书籍的位置或内容。
1.2 节点的核心类型与关系
DOM 节点的类型包括:
- 元素节点(Element Node):对应 HTML 标签,如
<div>
、<a>
。 - 属性节点(Attribute Node):附加在元素上的属性,如
id="main"
。 - 文本节点(Text Node):元素内的文本内容,如
<p>欢迎来到我的网站</p>
中的文本。 - 注释节点(Comment Node):以
<!-- -->
包裹的内容。 - 文档节点(Document Node):整个 HTML 文档的根节点。
节点之间通过父子关系、兄弟关系等连接,例如:
<div id="container"> <!-- 父节点 -->
<p>第一段内容</p> <!-- 子节点 -->
<p>第二段内容</p> <!-- 子节点 -->
</div>
上述代码中,<div>
是父节点,两个 <p>
是子节点,它们彼此是兄弟节点。
二、节点列表的核心概念:NodeList 与 HTMLCollection
2.1 什么是节点列表?
当通过 JavaScript 查询多个 DOM 节点时,返回的结果通常是一个 节点列表(Node List)。常见的节点列表类型包括:
- NodeList:动态更新的列表,常通过
document.querySelectorAll()
获取。 - HTMLCollection:静态列表,常通过
document.getElementsByTagName()
获取。
关键区别:
| 特性 | NodeList | HTMLCollection |
|---------------|-----------------------------------|---------------------------------|
| 动态性 | 实时更新,与 DOM 同步 | 不自动更新,需重新查询 |
| 可迭代性 | 支持 for...of
和 Array.from()
| 仅支持 for
循环 |
| 索引访问 | 通过 [index]
获取元素 | 通过 [index]
或命名属性访问 |
比喻:将 NodeList 想象为一个“活”的图书馆目录,当书籍位置变化时,目录会自动更新;而 HTMLCollection 则像一本固定的目录册,除非手动刷新,否则不会反映最新变化。
2.2 常用方法与属性
2.2.1 NodeList 的常用操作
- 遍历节点:使用
for...of
或Array.prototype.forEach()
:const paragraphs = document.querySelectorAll("p"); for (const p of paragraphs) { p.style.color = "red"; // 修改所有段落文字颜色 }
- 转换为数组:通过
Array.from()
或扩展运算符[...nodeList]
:const paragraphsArray = Array.from(document.querySelectorAll("div")); paragraphsArray.forEach(div => console.log(div.innerHTML));
2.2.2 HTMLCollection 的典型用法
HTMLCollection 常用于通过标签名或表单元素查询节点:
// 获取所有 <div> 元素
const divs = document.getElementsByTagName("div");
// 通过索引访问
console.log(divs[0]); // 第一个 div
// 通过名称属性访问(如表单元素)
const formInputs = document.forms["myForm"].elements;
formInputs["username"].value = "guest"; // 设置表单值
三、操作节点列表的实战技巧
3.1 常见操作场景与代码示例
3.1.1 动态添加与移除节点
通过 NodeList
或 HTMLCollection
可以批量操作节点。例如,动态生成列表项:
<ul id="taskList"></ul>
<script>
// 创建三个列表项
const tasks = ["任务1", "任务2", "任务3"];
const list = document.getElementById("taskList");
tasks.forEach(task => {
const li = document.createElement("li");
li.textContent = task;
list.appendChild(li); // 添加到列表末尾
});
// 移除第一个任务
list.removeChild(list.children[0]);
</script>
3.1.2 根据条件筛选节点
结合 NodeList
和数组方法,可以实现复杂筛选:
// 获取所有未完成的待办事项
const todos = document.querySelectorAll(".todo-item");
const incomplete = Array.from(todos).filter(todo => !todo.classList.contains("completed"));
// 隐藏未完成项
incomplete.forEach(item => item.style.display = "none");
3.2 性能优化与注意事项
- 避免频繁操作 DOM:批量修改节点后一次性提交,而非逐个操作。
- 使用
closest()
精确查询父节点:const targetDiv = document.querySelector(".item").closest("div.parent"); // 定位最近的父级 div
- 注意节点列表的实时性:
const items = document.querySelectorAll(".item"); items[0].remove(); // 移除后,items 列表会自动更新,items.length 减少
四、典型应用场景与案例分析
4.1 实例 1:动态表格数据绑定
假设需要根据后端返回的数据动态渲染表格:
<table>
<thead>
<tr>
<th>名称</th>
<th>价格</th>
</tr>
</thead>
<tbody id="productList"></tbody>
</table>
<script>
const products = [
{ name: "笔记本", price: 899 },
{ name: "鼠标", price: 49 }
];
const tbody = document.getElementById("productList");
products.forEach(product => {
const row = document.createElement("tr");
row.innerHTML = `<td>${product.name}</td><td>${product.price}</td>`;
tbody.appendChild(row);
});
</script>
4.2 实例 2:交互式筛选功能
通过用户输入动态过滤列表项:
<input type="text" id="filterInput" placeholder="搜索">
<div id="items">
<div class="item">苹果</div>
<div class="item">香蕉</div>
<div class="item">橙子</div>
</div>
<script>
const items = document.querySelectorAll(".item");
document.getElementById("filterInput").addEventListener("input", (e) => {
const query = e.target.value.toLowerCase();
items.forEach(item => {
const text = item.textContent.toLowerCase();
item.style.display = text.includes(query) ? "block" : "none";
});
});
</script>
五、常见问题与最佳实践
5.1 常见误区及解决方案
-
误区 1:误认为所有查询方法返回的都是数组
解决:使用Array.from()
或扩展运算符将 NodeList 转换为数组:const nodeList = document.querySelectorAll("div"); const array = [...nodeList]; // 使用扩展运算符
-
误区 2:过度依赖
HTMLCollection
的实时性
解决:若需动态操作,优先使用document.querySelectorAll()
返回的 NodeList。
5.2 高级技巧:结合 CSS 选择器优化查询
利用 CSS 选择器的灵活性,可以精准定位节点:
// 获取所有 class 包含 "active" 的按钮
const activeButtons = document.querySelectorAll("button.active");
// 获取父元素为 #container 的 input
const inputs = document.querySelectorAll("#container > input");
结论
掌握 JavaScript HTML DOM 节点列表是开发者从入门到进阶的关键一步。通过理解节点的层级关系、灵活使用 NodeList 和 HTMLCollection,并结合实际案例实践,可以显著提升页面交互的开发效率。无论是构建简单的数据展示,还是复杂的动态界面,节点列表始终是连接 JavaScript 逻辑与 HTML 结构的桥梁。建议读者通过不断练习,尝试将本篇文章中的示例代码扩展为完整的项目,逐步深化对 DOM 操作的理解。