HTML DOM firstChild 属性(超详细)

更新时间:

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

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

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

在 Web 开发中,HTML DOM(文档对象模型)提供了强大的接口,允许开发者通过 JavaScript 动态操作网页内容。其中,firstChild 属性作为节点操作的基础功能之一,常用于访问元素的第一个子节点。然而,由于其特性容易引发混淆,许多开发者在初次使用时会遇到意外结果。本文将从基础概念出发,结合实际案例,深入解析 HTML DOM firstChild 属性 的用法、潜在问题及解决方案,帮助读者快速掌握这一工具。


一、HTML DOM 的基础概念

1.1 节点与节点树

HTML 文档本质上是一个由节点构成的树状结构。每个元素(如 <div><p>)、文本内容、注释甚至文档本身都是节点。例如,以下代码片段包含多个节点:

<div id="container">
  <p>第一个段落</p>
  <!-- 这是一个注释 -->
  <p>第二个段落</p>
</div>

此结构中:

  • <div> 是父节点,包含两个 <p> 子节点和一个注释节点
  • 每个 <p> 元素内部的文本(如“第一个段落”)是文本节点
  • 注释节点也是独立的节点类型

比喻:可将 DOM 比作一棵家族树,每个节点代表一个家庭成员,父节点是“家长”,子节点是“子女”,而文本或注释则是“家族记录”。

1.2 节点类型与常用属性

每个节点对象包含多个属性,如:

  • nodeName:返回节点名称(如元素的标签名)
  • nodeType:返回节点类型(如 1 表示元素节点,3 表示文本节点)
  • parentNode:指向父节点的引用
  • firstChild:指向第一个子节点的引用

1.3 firstChild 的作用

firstChild 属性返回指定节点的第一个子节点,无论该节点是元素、文本还是注释。其核心特性是:

  • 无类型限制:返回所有类型的子节点,不区分元素与非元素
  • 按顺序检索:从左到右遍历节点树

二、firstChild 属性的使用场景与代码示例

2.1 基础用法

通过以下步骤演示如何使用 firstChild

  1. 获取目标父节点
  2. 调用其 firstChild 属性
// 获取父节点
const container = document.getElementById('container');

// 获取第一个子节点
const firstNode = container.firstChild;

console.log(firstNode.nodeName); // 输出 "#text"(因第一个子节点为换行符或空格)

注意

  • 若父节点内部有空格或换行符,firstChild 可能返回文本节点(如 #text)而非预期的元素节点
  • 需通过 nodeTypenodeName 判断节点类型

2.2 典型案例:遍历节点树

假设需遍历一个列表的子节点:

<ul id="list">
  <!-- 注释 -->
  <li>苹果</li>
  <li>香蕉</li>
</ul>
const list = document.getElementById('list');
let currentNode = list.firstChild;

while (currentNode) {
  if (currentNode.nodeType === 1) { // 过滤非元素节点
    console.log(currentNode.textContent);
  }
  currentNode = currentNode.nextSibling;
}

输出结果

苹果  
香蕉  

三、常见问题与解决方案

3.1 问题一:返回非元素节点

现象:当父节点包含文本节点(如换行符)时,firstChild 可能返回意外结果。
原因:HTML 中的空格、换行符会被解析为文本节点。
解决方案

  • 使用 firstElementChild(仅返回元素节点,需注意浏览器兼容性)
  • 手动过滤非元素节点
// 方法一:使用 firstElementChild
const firstElement = container.firstElementChild;
console.log(firstElement.nodeName); // 输出 "P"

// 方法二:循环查找第一个元素节点
function getFirstElement(node) {
  let child = node.firstChild;
  while (child) {
    if (child.nodeType === 1) return child;
    child = child.nextSibling;
  }
  return null;
}

3.2 问题二:空节点的情况

当父节点无子节点时,firstChild 返回 null。需在代码中处理该情况,避免报错:

if (container.firstChild) {
  // 安全操作
} else {
  console.log("无子节点");
}

四、进阶技巧与最佳实践

4.1 结合其他节点属性

通过 firstChildnextSibling 等属性组合,可实现复杂操作:

// 遍历所有子元素并添加类名
let child = container.firstChild;
while (child) {
  if (child.nodeType === 1) {
    child.classList.add('highlight');
  }
  child = child.nextSibling;
}

4.2 与 CSS 选择器对比

虽然 firstChild 功能强大,但需注意与 CSS 选择器(如 :first-child)的区别:

  • :first-child 仅匹配元素节点
  • firstChild 包含所有节点类型

示例对比

/* CSS 选择器 */
div > p:first-child { color: red; } // 仅匹配第一个 `<p>` 元素

4.3 性能优化建议

频繁操作 DOM 可能影响性能,建议:

  1. 将节点引用缓存到变量中
  2. 批量操作而非逐个修改
  3. 使用 querySelector 替代递归查找

五、综合案例:动态修改 DOM 结构

5.1 需求场景

创建一个可动态增删子节点的列表:

<div id="parent">
  <div class="item">项目 1</div>
  <div class="item">项目 2</div>
</div>

5.2 实现步骤

  1. 获取父节点
  2. 插入新节点到第一个位置
  3. 移除最后一个子节点
// 获取父节点
const parent = document.getElementById('parent');

// 插入新节点到最前面
const newFirst = document.createElement('div');
newFirst.textContent = '新项目';
newFirst.className = 'item';
parent.insertBefore(newFirst, parent.firstChild);

// 移除最后一个子节点
const lastChild = parent.lastChild;
if (lastChild.nodeType === 1) {
  parent.removeChild(lastChild);
}

结果:列表变为 新项目 → 项目 1,原 项目 2 被移除。


六、总结

HTML DOM firstChild 属性 是操作节点树的基础工具,但其返回所有类型子节点的特性需要开发者谨慎使用。通过结合 nodeType 过滤、使用 firstElementChild 替代或循环遍历,可有效避免常见陷阱。掌握该属性后,开发者能更灵活地动态调整网页内容,实现复杂的交互功能。

关键要点回顾

  • firstChild 返回所有类型节点(包括文本、注释)
  • 使用 nodeTypefirstElementChild 筛选元素节点
  • 结合 nextSibling 等属性实现节点遍历

希望本文能帮助读者在实际开发中高效运用这一工具,进一步探索 DOM 操作的更多可能性。

最新发布