高性能递归算法实现HTML嵌套列表转换为树状JSON结构
浏览器中DOM深度一旦超过50层,就很容易触发递归调用栈限制,而在实际页面中,嵌套列表的深度通常在8到12层之间。在这种情况下,纯递归基本无法胜任。
### 如何安全提取 `- ` 不一定紧跟在后面。这意味着不能简单依赖 `children` 遍历,必须显式定位每个 `
- ` 下的第一个 `
- `,并将其作为子节点容器。
具体操作上:
* 首先通过 `querySelectorAll('li')` 获取所有 `
- ` 元素,并按照DOM顺序逐个处理。这样能有效避免因CSS属性 `display:none` 或JavaScript动态插入导致的节点遗漏。 * 对每个 `
- `,使用 `nextElementSibling` 向下查找最近的 `
- `,而不是用 `li.querySelector('ul')`。后者容易误抓兄弟节点下的子菜单,造成层级混乱。
* 如果找到了对应的 `
- ` 的文本内容需要清理:剔除换行、多余空格、` `,然后使用 `textContent.trim()` 而不是 `innerText`(后者受CSS影响,结果可能不准确)。 * 如果需要保留原始HTML片段(例如含有图标标签),可以使用 `innerHTML.replace(/< \/?ul[^]*?>/gi, '')` 剥离包裹标签。不过要注意XSS风险,建议添加白名单过滤。 ### 深度超过20层时,改用迭代+栈模拟递归 虽然Chrome V8的默认调用栈限制大约为10000帧,但实际测试表明,DOM深度一旦超过20层,就可能触发 `RangeError: Maximum call stack size exceeded`,尤其在旧版Safari中更加敏感。这种情况下必须切换策略。 使用数组模拟栈:`const stack = [{ ul: rootUl, depth: 0, parent: null }];` 每次弹出一个节点,处理其下的 `
- `,然后将子 `
- ` 推入栈中。
* 每一层生成的对象都必须带有 `id` 字段(可以用 `Math.random().toString(36).substr(2, 9)` 生成轻量唯一键),否则后续无法关联父子关系。
* 迭代版本的性能会略低(多一次循环),但内存可控,没有栈溢出风险。特别适合CMS导出菜单、文档大纲等深度不可控的场景。
真正的核心难点不在于如何编写递归,而在于判断何时应该避免递归。当DOM层级不断加深时,就需要认真考虑:是否应该采用平面列表配合depth字段来替代嵌套JSON结构?许多前端树组件(如 antd Tree)在内部早已将数据扁平化处理,渲染时才按depth计算缩进。这一细节常被忽视,却对长期维护影响深远。我的结论是:与其在20层以上强行使用递归,不如从一开始就转向扁平化数据结构。
- `,则递归解析它;如果未找到,则将 `children` 设置为空数组。
### `parseListToTree()` 函数必须隔离作用域与状态
一个常见的失误点:将 `result` 数组或 `currentNode` 对象传入递归函数进行累加,导致所有层级共享同一个引用,子节点被重复推送到父节点两次。正确的做法是:让每一层递归都返回一个全新的数组,由上一层决定是否合并。
函数签名应设计为 `function parseListToTree(ulElement) { ... return childrenArray; }`,坚决不接受外部变量注入。
* 每个 `
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
如何用HTML制作带评分和评论的产品详情区域
构建评分评论模块需兼顾语义化与无障碍访问。评分区使用fieldset与单选按钮实现互斥选择,评论列表采用ol的reversed倒序展示。提交时阻止页面刷新,校验失败保留内容,成功则异步更新列表与平均分。平均分保留一位小数,并通过aria-live确保辅助技术感知动态更新,以保障键盘与屏幕阅读器用户体验。
Django基于主键动态生成文章详情页URL完整教程
在Django项目规划文章详情页URL时,很多开发者会纠结:该用可读性强的slug,还是简单可靠的主键(pk)?如果你的网站内容尚未上线,或你希望彻底摆脱维护slug字段的麻烦,那么将URL从slug切换为pk,无疑是一次一劳永逸的明智选择。 这一过程并不复杂,核心在于同步调整路由、视图和模板三部分
使用BigInt对原始128位UUID进行二进制解析与逻辑运算
在处理全局唯一标识符(UUID)时,我们常常需要深入到其二进制层面进行解析、比较或生成变体。JavaScript 原生的 BigInt 类型,凭借其处理任意精度整数的能力,为直接操作 128 位的 UUID 原始数据提供了可能。不过,这里有个关键前提:BigInt 并不能直接“理解”带连字符的 UU
用new操作符四步模拟实现自定义myNew
要真正掌握 JavaScript 中的 new 操作符,与其死记硬背,不如亲手模拟一遍它的内部实现机制。这个过程能帮助你彻底打通原型、构造函数、this 绑定等核心概念。简单来说,模拟 new 可以拆解为四个清晰的步骤:创建一个继承自构造函数原型的新对象,将构造函数的 this 绑定到这个新对象并执
利用闭包构建偏函数简化多参数API调用
在Python编程中,我们常常面临需要重复调用某个函数,而每次仅少数参数发生变化的情况。此时,偏函数(Partial Application)便能发挥巨大作用——它允许我们预先固定部分参数,生成一个调用时更简洁的新函数。你可能已经使用过functools partial,但你是否思考过它的底层机制究
- 日榜
- 周榜
- 月榜
相关攻略
2026-07-05 06:59
2026-07-05 06:58
2026-07-05 06:58
2026-07-05 06:58
2026-07-05 06:58
2026-07-05 06:57
2026-07-05 06:57
2026-07-05 06:57
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

