跟着 MDN 学 HTML day_50:(深入理解 DOM 中的 Text 节点)

在 Web 开发中,DOM(文档对象模型)是我们与网页内容交互的核心接口。无论是操作元素、修改样式,还是读取和写入内容,几乎所有的动态行为都离不开对 DOM 的操控。而在 DOM 树形结构的最底层,有一种节点常常被忽视,却又无处不在,那就是 Text 节点。

今天这篇文章,我们将系统性地学习 Text 节点相关的知识,包括它的构造函数、核心属性以及一个非常实用的实例方法。通过丰富的示例代码,我们会逐步理解这些概念在实际开发中的用途。

一、什么是 Text 节点

在 DOM 树中,Text 节点是用于承载文本内容的节点类型。它继承自 CharacterData,而 CharacterData 又继承自 Node,最后 Node 继承自 EventTarget。

从继承链我们可以看出,Text 节点是一个功能完整的对象,拥有事件处理能力、文本操作能力和通用节点操作能力。虽然它在视觉上不如元素节点显眼,但在结构化文档和内容处理上却占据重要地位。

示例:一个简单 HTML 文档中的文本节点

html 复制代码
<html lang="en" class="e">
  <head>
    <title>Aliens?</title>
  </head>
  <body>
    Why yes.
  </body>
</html>

在这个文档中,实际上存在 5 个文本节点:
开始标签后的一个换行符加四个空格,内容是 "\n " 元素内的文本 "Aliens?" 结束标签后的一个换行符加两个空格,内容是 "\n " 开始标签后的一个换行符加两个空格,内容是 "\n " 元素本身的全部内容,包括换行和文本 "\n Why yes.\n \n\n"

每个这样的文本内容都会在内存中形成一个 Text 节点对象,供我们通过 JavaScript 访问和操作。

二、Text 构造函数

Text 构造函数 Text() 可以创建一个新的文本节点。它接受一个字符串参数,该参数将成为新节点的文本内容。

语法

javascript 复制代码
let textNode = new Text("Hello World");

示例:使用 Text 构造函数创建并插入节点

html 复制代码
<div id="container"></div>

<script>
  const container = document.getElementById("container");
  
  // 创建一个新的文本节点
  const textNode = new Text("这是动态添加的文本内容。");
  
  // 将文本节点添加到 div 中
  container.appendChild(textNode);
</script>

在这个例子中,我们通过 Text 构造函数创建了节点,并使用 appendChild 将其插入到 DOM 树中。这种创建方式比直接使用 innerHTML 更安全,也更具可控性,尤其是在处理纯文本时避免了 XSS 风险。

三、实例属性 inherited 概述

Text 节点继承了 CharacterData、Node 和 EventTarget 的所有实例属性。这些继承关系意味着 Text 节点不仅能存储文本内容,还具备节点的结构性、导航性以及事件机制。

举个例子,Text 节点可以通过 parentNode 获取父元素,通过 nextSibling 获取下一个兄弟节点,并且可以调用 addEventListener 注册事件监听器。这种强大能力来源于层层继承的设计。

四、Text.wholeText 属性

定义

wholeText 是一个只读属性,它会返回与当前 Text 节点逻辑上相邻的所有 Text 节点的完整文本内容,并按文档顺序将其拼接成一个字符串。

这个属性的特别之处在于,它能让我们获取一块连续的文本,即使这些文本在实际 DOM 树中被元素节点(如 或 )分隔开。

注意: 调用 wholeText 不会修改 DOM 结构,这一点与调用 Node.normalize() 不同。

示例:获取连续文本块

html 复制代码
<p>
  徒步旅行很不错!
  <strong>平淡无奇的选举报道!</strong>
  然而,<a href="https://zh.wikipedia.org/wiki/缺席投票">投票</a
  >是一件棘手的事情。
</p>
javascript 复制代码
const paragraph = document.querySelector("p");

// 删除中间的 <strong> 元素
paragraph.removeChild(paragraph.childNodes[1]);

// 获取第一个文本节点的完整相邻文本
console.log(`'${paragraph.childNodes[0].wholeText}'`);
// 输出:'徒步旅行很不错!然而, '

在执行删除操作后,原本被 分隔的两个文本节点 "徒步旅行很不错!" 和 "然而," 变成了相邻节点。通过 wholeText 属性,我们能够一次性获取拼接后的完整文本。这种用法在富文本编辑器、内容提取和文本分析中非常实用。

五、Text.assignedSlot 属性

定义

assignedSlot 是一个只读属性,返回与当前 Text 节点相关联的 元素对象,如果文本节点没有分配到任何 slot,则返回 null。

该属性通常结合 Web Components 中的 Shadow DOM 使用。在一个组件内部使用 时,外部的文本节点会被映射到对应的 slot 上。

示例:在 Shadow DOM 中观察 assignedSlot

html 复制代码
<my-component>
  这是一段被投影的文本
</my-component>

<script>
  customElements.define("my-component", class extends HTMLElement {
    constructor() {
      super();
      const shadow = this.attachShadow({ mode: "open" });
      shadow.innerHTML = `<slot></slot>`;
    }
  });

  const component = document.querySelector("my-component");
  const textNode = component.childNodes[0];  // 文本节点

  // 获取该文本节点对应的 slot
  console.log(textNode.assignedSlot); 
  // 输出:<slot></slot> 元素对象
</script>

在这个示例中,外部传入的文本节点 "这是一段被投影的文本" 被 捕获。通过 assignedSlot 属性,文本节点可以反向找到自己所属的 元素。这种机制在 Web Components 开发中非常关键,有助于实现复杂的内容分发逻辑。

六、Text.splitText 方法

定义

splitText(offset) 方法可以在指定的偏移量处将一个 Text 节点分割为两个独立的兄弟节点。分割后,原节点保留从开头到 offset(不包含 offset 处字符)的文本,而新的节点包含剩余部分。

语法

javascript 复制代码
let newNode = textNode.splitText(offset);

offset:整数索引,在此位置之前切分文本。

返回值:一个新的 Text 节点,包含原节点中 offset 之后的文本。

如果 offset 等于文本长度,则返回一个空文本节点。如果 offset 小于 0 或大于文本长度,会抛出 INDEX_SIZE_ERR 异常。若文本节点为只读,则抛出 NO_MODIFICATION_ALLOWED_ERR 异常。

示例:在文本中间插入元素

html 复制代码
<p id="p">foobar</p>
javascript 复制代码
const p = document.getElementById("p");

// 获取文本节点
const foobar = p.firstChild;

// 在索引 3 处分割文本
const bar = foobar.splitText(3);

// 创建一个新的 <u> 元素
const u = document.createElement("u");
u.appendChild(document.createTextNode(" new content "));

// 将 <u> 插入到分割后的两个文本节点之间
p.insertBefore(u, bar);

// 最终结构:<p id="p">foo<u> new content </u>bar</p>

在这个例子中,"foobar" 被分割成了 "foo" 和 "bar" 两个文本节点,然后我们在它们之间插入了一个 ++元素。这种技术常用于实现富文本编辑器中的分隔与包裹操作。++

七、Node.normalize 与 splitText 的关系

当我们在 DOM 中对文本节点进行多次分割、插入或删除操作后,可能会产生大量零散的相邻文本节点。为了简化结构,可以使用 Node.normalize() 方法,将相邻的文本节点合并为一个。

示例:normalize 的使用

html 复制代码
<p id="text-block">ABCDEF</p>
javascript 复制代码
const p = document.getElementById("text-block");
const text = p.firstChild;

// 分割文本两次
text.splitText(3);
text.splitText(1);

console.log(p.childNodes.length); // 此时有 3 个文本节点

// 合并所有相邻文本节点
p.normalize();

console.log(p.childNodes.length); // 合并后只有 1 个文本节点

normalize() 不会改变文本内容的显示效果,但会让 DOM 树更加整洁,有利于性能优化和后续操作。

八、浏览器兼容性

Text 接口及其构造函数、属性和方法在现代主流浏览器中都得到了广泛支持,属于基线(Baseline)广泛可用的特性。具体来说,Chrome、Firefox、Safari 和 Edge 的最新版本均支持这些内容。

在实际项目中使用时,如果是面向现代浏览器环境,可以放心地直接应用这些特性。而在需要兼容较旧的浏览器(如 Internet Explorer)时,可能需要额外做功能检测或使用 polyfill。

九、实践场景总结

Text 节点的操作在前端开发中有着丰富的应用场景,例如:

实现富文本编辑器中的文本分割、加粗、链接化

搜索高亮功能中对文本内容进行精准切分并插入 标签

构建 Web Components 时管理 slot 内容

对用户输入内容进行 XSS 安全转义处理

动态生成模板内容并保持结构清晰

理解 Text 节点的属性和方法,能让我们在处理底层文本操作时更加得心应手,而不仅仅是依赖 innerHTML 这种粗颗粒度的操作方式。

十、总结

今天的学习内容聚焦于 DOM 中的 Text 节点,我们从它的基本定义、继承链开始,逐步深入了解了其构造函数、wholeText 属性、assignedSlot 属性以及非常有用的 splitText 方法。每一个知识点都通过可运行的示例进行了演示,帮助我们在实际开发中快速上手。

Text 节点虽然看似简单,却是构成 HTML 文档内容的最小单位。掌握它的特性和用法,能够让我们在处理复杂文本逻辑时更加游刃有余,也为后续深入 DOM 操作打下了坚实基础。

希望通过本篇文章,你能够对 Text 节点有一个全面而系统的认识,并能在实际项目中灵活运用这些技术。


想要解锁更多HTML 核心标签实战、前端零基础入门干货、开发避坑全指南吗?
持续关注,后续将更新CSS 布局实战、JavaScript 交互基础、全站导航开发等硬核内容,带你从新手快速进阶,轻松搞定前端开发!

相关推荐
ZC跨境爬虫1 小时前
跟着 MDN 学 HTML day_51:(深入理解 XPathEvaluator 接口)
前端·javascript·ui·html·音视频
wjykp1 小时前
5.cypher语句组合与复杂操作
linux·前端·javascript
梦无矶1 小时前
nrm自动设置npm镜像源
前端·npm·node.js
鲤鱼_5991 小时前
记录——前端开发IDEA需要的插件
前端
摘星编程1 小时前
基于 JiuwenSwarm AgentTeam 构建混沌工程自动化实战
前端·chrome
nashane2 小时前
HarmonyOS 6学习:Web组件与JavaScript交互的三大高频问题与终极解决方案
前端·学习·harmonyos
a1117762 小时前
3D书籍滑动展示组件(html 开源)
html
顾随2 小时前
(2)达梦数据库--SQl基础实践
前端·数据库·sql
键盘飞行员2 小时前
Windsurf + Claude 4.7 前端开发:用 ui-ux-pro-max 根治 “AI 味”、实现全站 UI 统一
前端·ui·ai编程