如何递归清理 HTML 结构:仅保留 li 标签,其余元素降级为纯文本

冬敏君_2190

冬敏君_2190

2026-01-14

324人浏览

原创

如何递归清理 HTML 结构:仅保留 li 标签,其余元素降级为纯文本

本文详解为何原递归函数无法处理 `

` 等非 `li` 元素,并提供基于 `for...of` 的健壮解决方案,确保所有非 `li` 元素(如 `

`、``、`

    `)被安全展开为其子文本节点,最终输出符合预期的纯净 HTML 片段。

问题根源在于 NodeList.prototype.forEach() 的执行时序与 DOM 树动态变更的冲突。当递归调用 testFn(e) 后立即执行 e.replaceWith(...e.childNodes) 时,e 被从 DOM 中移除,其子节点被插入到原位置——这会修改当前 node.childNodes 的长度和索引顺序。而 forEach() 内部是基于初始快照遍历的,后续迭代仍按原始 NodeList 进行,导致部分节点被跳过(尤其是紧邻被替换节点之后的兄弟节点),造成

等元素未被处理。

使用 for...of 循环可规避该问题,因为它在每次迭代时都重新获取当前 childNodes 的迭代器,能响应实时 DOM 变化;更重要的是,它使控制流更清晰、避免闭包陷阱,便于逻辑调试。

以下是修正后的完整实现:

let html = `
<ol>
<li>
<a href="https://www.php.cn/link/93ac0c50dd620dc7b88e5fe05c70e15b">foo link text</a>;</li>
<li>
<a href="https://www.php.cn/link/93ac0c50dd620dc7b88e5fe05c70e15b">bar link text</a>;</li>
</ol><p>Paragraph text baz and biz text.</p><div class="aritcle_card flexRow artxards">
											<div class="artcardd flexRow">
												<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill12116" title="DeepBI DHTML 页面生成器"><img
														src="https://img.php.cn/upload/skill/001/246/273/6adaf20d3191a227.jpg" alt="DeepBI DHTML 页面生成器" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
												<div class="aritcle_card_info flexColumn">
													<a rel="nofollow" href="/xiazai/skill12116" title="DeepBI DHTML 页面生成器" class="overflowclass">DeepBI DHTML 页面生成器</a>
													<p class="overflowclass">生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力:

- 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面;  
- 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”;  
- 提及位于 `apps/console/src/featur</p>
												</div>
												<a rel="nofollow" href="/xiazai/skill12116" title="DeepBI DHTML 页面生成器" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
												</a>
											</div>
										</div>
<p>Paragraph text.</p>
`;

html = `${html}`;
const parsed = new DOMParser().parseFromString(html, 'text/html');

function flattenNonLiElements(node) {
  for (const child of node.childNodes) {
    // 先递归处理子节点(深度优先)
    flattenNonLiElements(child);

    // 仅对元素节点进行判断和替换
    if (child.nodeType !== Node.ELEMENT_NODE) continue;

    // 仅保留 
  • ,其余元素全部展开为子节点(含文本、注释等) if (child.nodeName.toLowerCase() !== 'li') { // 注意:replaceWith(...) 会将 child 替换为其所有直接子节点 // 若 child 无子节点(如空

    ),则被替换为空白(即消失) child.replaceWith(...child.childNodes); } } } flattenNonLiElements(parsed.body); console.log(parsed.body.innerHTML); // 输出: //
  • foo link text;
  • //
  • bar link text;
  • // Paragraph text baz and biz text. // Paragraph text.

    ✅ 关键要点总结:

    • ❌ 避免在 DOM 修改过程中使用 forEach() 遍历 childNodes;
    • ✅ 优先选用 for...of 或传统 for (let i = 0; i
    • ✅ replaceWith(...childNodes) 是安全展开元素内容的标准方式,天然支持混合节点类型(文本、元素、注释);
    • ⚠️ 注意:若目标元素(如

      )内含嵌套 HTML(如 ),它们也会被一并展开——这正是需求所要求的“只留文本”效果;如需保留特定内联标签,需额外白名单逻辑;

    • ? 建议在真实项目中添加边界检查(如 node && node.childNodes),增强鲁棒性。

    该方案简洁、可预测,适用于任意层级 HTML 结构的语义化精简处理。

    前端入门到VUE实战笔记:立即使用
    在学习笔记中,你将探索 前端 的入门与实战技巧!

    相关文章

    HTML速学教程(入门课程)
    HTML速学教程(入门课程)

    HTML怎么学习?HTML怎么入门?HTML在哪学?HTML怎么学才快?不用担心,这里为大家提供了HTML速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!

    下载

    相关标签:

    html node 递归函数

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

    相关专题

    更多
    php中foreach用法
    php中foreach用法

    本专题整合了php中foreach用法的相关介绍,阅读专题下面的文章了解更多详细教程。

    2025.12.04

    858

    13

    length函数用法
    length函数用法

    length函数用于返回指定字符串的字符数或字节数。可以用于计算字符串的长度,以便在查询和处理字符串数据时进行操作和判断。 需要注意的是length函数计算的是字符串的字符数,而不是字节数。对于多字节字符集,一个字符可能由多个字节组成。因此,length函数在计算字符串长度时会将多字节字符作为一个字符来计算。更多关于length函数的用法,大家可以阅读本专题下面的文章。

    2023.09.19

    2007

    6

    go语言闭包相关教程大全
    go语言闭包相关教程大全

    本专题整合了go语言闭包相关数据,阅读专题下面的文章了解更多相关内容。

    2025.07.29

    5233

    19

    DOM是什么意思
    DOM是什么意思

    dom的英文全称是documentobjectmodel,表示文件对象模型,是w3c组织推荐的处理可扩展置标语言的标准编程接口;dom是html文档的内存中对象表示,它提供了使用javascript与网页交互的方式。想了解更多的相关内容,可以阅读本专题下面的文章。

    2024.08.14

    6541

    7

    Go-Zero API开发使用教程
    Go-Zero API开发使用教程

    本专题聚焦Go-Zero的API开发,拆解.api描述文件的语法结构、路由与分组定义、参数绑定与校验规则,说明统一响应体、JWT鉴权、跨域与接口文档生成的落地方式,并给出网关聚合与接口测试的实践建议。

    2026.11.12

    100

    15

    Go-Zero安装与goctl环境配置教程
    Go-Zero安装与goctl环境配置教程

    本专题围绕Go-Zero的安装与工具链配置展开,讲清Go版本要求、goctl安装方式、代理镜像、protoc依赖与环境变量设置,说明多版本共存、升级回退与CI流水线安装的做法,并整理安装阶段的常见报错与验证步骤。

    2026.11.12

    60

    15

    Go-Zero零基础入门教程
    Go-Zero零基础入门教程

    本专题整理Go-Zero的入门知识,从框架定位、环境准备到跑通第一个API服务,讲清目录分层、配置加载、日志与中间件的基本用法,并对比Gin、Kratos的差异,帮助Go开发者建立整体认知,判断它是否适合当前项目。

    2026.11.12

    60

    15

    Postman身份认证怎么配置
    Postman身份认证怎么配置

    本专题从实际API接口调试场景出发,讲解Postman身份认证的完整配置流程,包括常见认证协议介绍、授权参数设置、访问令牌填写、OAuth 2.0授权及认证失败排查,帮助用户正确完成接口授权与访问验证。

    2026.11.06

    140

    12

    Postman请求头Headers怎么设置
    Postman请求头Headers怎么设置

    围绕Postman HTTP请求头配置展开,讲解Headers选项的具体使用方式,包括Key和Value参数填写、请求头信息添加、常见Header字段设置及请求头修改方法,帮助用户解决接口调试过程中遇到的请求头配置问题。

    2026.11.06

    120

    13

    热门下载

    更多
    网站特效
    /
    网站源码
    /
    网站素材
    /
    前端模板

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    GDB 17.2 官方文档集合
    GDB 17.2 官方文档集合

    共0课时 | 0人学习

    Bootstrap 入门安装配置
    Bootstrap 入门安装配置

    共0课时 | 0人学习

    38+ PhpStorm 提示和技巧
    38+ PhpStorm 提示和技巧

    共1课时 | 244人学习