JavaScript HTML DOM 节点列表(长文解析)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 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...ofArray.from() | 仅支持 for 循环 |
| 索引访问 | 通过 [index] 获取元素 | 通过 [index] 或命名属性访问 |

比喻:将 NodeList 想象为一个“活”的图书馆目录,当书籍位置变化时,目录会自动更新;而 HTMLCollection 则像一本固定的目录册,除非手动刷新,否则不会反映最新变化。

2.2 常用方法与属性

2.2.1 NodeList 的常用操作

  • 遍历节点:使用 for...ofArray.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 动态添加与移除节点

通过 NodeListHTMLCollection 可以批量操作节点。例如,动态生成列表项:

<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 操作的理解。

最新发布