本文介绍一种递归方法,将符合规范的嵌套 <ul> 结构(每个 <li> 可包含文本及可选子 <ul>)精准转换为 JavaScript 嵌套数组,保持层级关系,支持无限深度,并正确提取 .operator 和 .condition 元素的文本内容。
本文介绍一种递归方法,将符合规范的嵌套 `
- ` 结构(每个 `
- ` 可包含文本及可选子 `
- `)精准转换为 javascript 嵌套数组,保持层级关系,支持无限深度,并正确提取 `.operator` 和 `.condition` 元素的文本内容。
要将嵌套 <ul> 转换为语义一致的嵌套数组(如 [operator1, [operator2, [condition1, condition2]], condition3]),关键在于:递归遍历每个 <li>,将其文本内容作为数组首项,再将子 <ul> 的解析结果展开合并为其后续元素。
注意原始 HTML 必须结构合法——即 <ul> 的直接子元素应为 <li>,而 <li> 内部可包含文本和(可选的)一个 <ul>。以下为修复并优化后的完整实现:
document.addEventListener('DOMContentLoaded', () => { const parseListItems = (element) => { const resultArray = []; // 仅遍历 direct children(避免误抓文本节点或注释) for (const child of element.children) { if (child.tagName === 'LI') { const textContent = child.textContent.trim(); const nestedUl = child.querySelector('ul'); if (nestedUl) { // 递归解析子 ul,结果为数组;拼接为 [当前文本, ...子数组] const nestedResult = parseListItems(nestedUl); resultArray.push([textContent, ...nestedResult]); } else { // 无子 ul:直接推入纯文本(保留原始语义,如 "condition1" 或 "operator1") resultArray.push(textContent); } } } return resultArray; }; const rootUl = document.querySelector('ul'); if (rootUl) { const result = parseListItems(rootUl); console.log(result); // 输出示例:["operator1", ["operator2", ["condition1", "condition2"], "condition3"]] } });✅ 关键设计说明:
- 使用 element.children(而非 querySelectorAll('li'))确保只处理直系 <li>,避免因 HTML 中换行/空格产生的文本节点干扰;
- child.textContent.trim() 安全提取所有文本(包括 .operator 和 .condition 的内容),无需依赖 class 名——只要结构正确,语义即由嵌套关系定义;
- 递归返回值始终是数组,[textContent, ...nestedResult] 实现“父项 + 展开子数组”的标准嵌套模式;
- 支持任意深度,时间复杂度为 O(n),n 为 DOM 节点总数。
⚠️ 注意事项:
立即学习“前端免费学习笔记(深入)”;
- 若 <li> 内含多个子元素(如 <span>、图标等),textContent 会合并全部文本;如需精确提取特定 class 的文本,请改用 child.querySelector('.operator, .condition')?.textContent?.trim();
- 不支持 <li> 后紧跟同级 <ul>(即 <li>...</li><ul>...</ul> 这种非法结构),必须保证 <ul> 是 <li> 的直接子元素;
- 若需返回带类型标记的对象(如 { type: 'operator', value: 'operator1', children: [...] }),可在递归中增强判断逻辑(例如检查 child.classList.contains('operator'))。
该方案简洁、健壮、无外部依赖,适用于动态生成的规则列表解析场景,是前端处理树形结构数据的经典实践。



















