当前位置: 首页
前端开发
高性能递归算法实现HTML嵌套列表转换为树状JSON结构

高性能递归算法实现HTML嵌套列表转换为树状JSON结构

热心网友 时间:2026-06-26
转载
先说结论:处理嵌套列表解析的核心策略是:优先使用迭代+栈模拟递归,而非纯递归。原因很简单:当浏览器中DOM深度达到20层以上时,递归极易引发栈溢出——这并非理论假设,而是实际开发中频繁遇到的真实现象。优化的目标不是追求速度,而是确保不遗漏节点、不混淆层级、不发生栈溢出。HTML嵌套列表转换为树状JSON结构的高性能递归算法 浏览器中DOM深度一旦超过50层,就很容易触发递归调用栈限制,而在实际页面中,嵌套列表的深度通常在8到12层之间。在这种情况下,纯递归基本无法胜任。 ### 如何安全提取 `
  • ` 的父子关系 需要注意的是,DOM树与JSON树的结构并不完全等同。`
  • ` 元素内部可能混杂文本、链接、图标等各种内容,且它的子 `
      ` 不一定紧跟在后面。这意味着不能简单依赖 `children` 遍历,必须显式定位每个 `
    • ` 下的第一个 `
        `,并将其作为子节点容器。 具体操作上: * 首先通过 `querySelectorAll('li')` 获取所有 `
      • ` 元素,并按照DOM顺序逐个处理。这样能有效避免因CSS属性 `display:none` 或JavaScript动态插入导致的节点遗漏。 * 对每个 `
      • `,使用 `nextElementSibling` 向下查找最近的 `
          `,而不是用 `li.querySelector('ul')`。后者容易误抓兄弟节点下的子菜单,造成层级混乱。 * 如果找到了对应的 `
            `,则递归解析它;如果未找到,则将 `children` 设置为空数组。 ### `parseListToTree()` 函数必须隔离作用域与状态 一个常见的失误点:将 `result` 数组或 `currentNode` 对象传入递归函数进行累加,导致所有层级共享同一个引用,子节点被重复推送到父节点两次。正确的做法是:让每一层递归都返回一个全新的数组,由上一层决定是否合并。 函数签名应设计为 `function parseListToTree(ulElement) { ... return childrenArray; }`,坚决不接受外部变量注入。 * 每个 `
          • ` 的文本内容需要清理:剔除换行、多余空格、` `,然后使用 `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层以上强行使用递归,不如从一开始就转向扁平化数据结构。
  • 来源:https://www.php.cn/faq/2684019.html

    游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

    同类文章
    更多
    如何用HTML制作带评分和评论的产品详情区域

    如何用HTML制作带评分和评论的产品详情区域

    构建评分评论模块需兼顾语义化与无障碍访问。评分区使用fieldset与单选按钮实现互斥选择,评论列表采用ol的reversed倒序展示。提交时阻止页面刷新,校验失败保留内容,成功则异步更新列表与平均分。平均分保留一位小数,并通过aria-live确保辅助技术感知动态更新,以保障键盘与屏幕阅读器用户体验。

    时间:2026-07-05 06:59
    Django基于主键动态生成文章详情页URL完整教程

    Django基于主键动态生成文章详情页URL完整教程

    在Django项目规划文章详情页URL时,很多开发者会纠结:该用可读性强的slug,还是简单可靠的主键(pk)?如果你的网站内容尚未上线,或你希望彻底摆脱维护slug字段的麻烦,那么将URL从slug切换为pk,无疑是一次一劳永逸的明智选择。 这一过程并不复杂,核心在于同步调整路由、视图和模板三部分

    时间:2026-07-05 06:58
    使用BigInt对原始128位UUID进行二进制解析与逻辑运算

    使用BigInt对原始128位UUID进行二进制解析与逻辑运算

    在处理全局唯一标识符(UUID)时,我们常常需要深入到其二进制层面进行解析、比较或生成变体。JavaScript 原生的 BigInt 类型,凭借其处理任意精度整数的能力,为直接操作 128 位的 UUID 原始数据提供了可能。不过,这里有个关键前提:BigInt 并不能直接“理解”带连字符的 UU

    时间:2026-07-05 06:58
    用new操作符四步模拟实现自定义myNew

    用new操作符四步模拟实现自定义myNew

    要真正掌握 JavaScript 中的 new 操作符,与其死记硬背,不如亲手模拟一遍它的内部实现机制。这个过程能帮助你彻底打通原型、构造函数、this 绑定等核心概念。简单来说,模拟 new 可以拆解为四个清晰的步骤:创建一个继承自构造函数原型的新对象,将构造函数的 this 绑定到这个新对象并执

    时间:2026-07-05 06:58
    利用闭包构建偏函数简化多参数API调用

    利用闭包构建偏函数简化多参数API调用

    在Python编程中,我们常常面临需要重复调用某个函数,而每次仅少数参数发生变化的情况。此时,偏函数(Partial Application)便能发挥巨大作用——它允许我们预先固定部分参数,生成一个调用时更简洁的新函数。你可能已经使用过functools partial,但你是否思考过它的底层机制究

    时间:2026-07-05 06:58
    热门专题
    更多
    刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
    洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
    思美人手游下载专区 思美人手游下载专区
    好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
    不思议迷宫手游下载合集 不思议迷宫手游下载合集
    百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
    jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
    宾果消消消原版下载大全 宾果消消消原版下载大全
    • 日榜
    • 周榜
    • 月榜