React中如何将WYSIWYG生成的标题转为多维结构用于目录组件?
在React中构建WYSIWYG编辑器内容的层级目录
嘿,你现在把h1、h2、h3分别存成独立数组的做法,虽然能把所有标题都提取出来,但最大的问题是丢失了它们之间的层级关联——毕竟h2是属于最近的那个h1的,h3是跟着最近的h2走的,分开存三个数组就没法对应这种父子关系啦。
更合适的方式是用嵌套对象结构来存储,每个节点包含title(标题文本)和children(子标题数组)两个属性,这样后续渲染成有序列表时,递归遍历起来会非常方便。
具体实现步骤
1. 按顺序提取所有标题(保留层级信息)
首先不要分开匹配h1、h2、h3,而是用一个正则一次性提取所有标题,同时记录它们的层级(h1对应level=1,以此类推):
const str = "<h1>h1-1</h1><h2>h2-1</h2><h3>h3-1</h3><p>something</p><h1>h1-2</h1><h2>h2-2</h2><h3>h3-2</h3>"; // 匹配h1-h3,捕获层级数字和标题文本 const headingPattern = /<h([1-3])>(.*?)<\/h\1>/g; let matches; const allHeadings = []; // 遍历所有匹配结果,收集成带层级的数组 while ((matches = headingPattern.exec(str)) !== null) { allHeadings.push({ level: parseInt(matches[1], 10), title: matches[2] }); }
2. 构建嵌套层级结构
接下来用栈来维护当前的层级路径,遍历所有标题,把它们放到对应的父节点下:
const buildHierarchy = (headings) => { const hierarchy = []; // 最终的层级结构数组 const stack = []; // 用来跟踪当前的层级路径 headings.forEach(heading => { const currentNode = { title: heading.title, children: [] }; // 弹出栈中所有层级 >= 当前标题层级的节点,找到当前节点的父节点 while (stack.length > 0 && stack[stack.length - 1].level >= heading.level) { stack.pop(); } if (stack.length === 0) { // 栈为空,说明是顶级h1,直接加入根数组 hierarchy.push(currentNode); } else { // 把当前节点加到父节点的children数组中 stack[stack.length - 1].children.push(currentNode); } // 将当前节点(带层级)压入栈,作为后续子标题的父节点候选 stack.push({ ...currentNode, level: heading.level }); }); return hierarchy; }; // 生成最终的层级目录结构 const tocHierarchy = buildHierarchy(allHeadings);
3. React组件递归渲染层级目录
最后写一个递归的React组件,把这个嵌套结构渲染成有序列表:
// 单个目录项组件 const TocItem = ({ item }) => { return ( <li> {item.title} {/* 如果有子标题,递归渲染子列表 */} {item.children.length > 0 && ( <ol> {item.children.map((child, idx) => ( <TocItem key={idx} item={child} /> ))} </ol> )} </li> ); }; // 目录总组件 const TableOfContents = ({ hierarchy }) => { return ( <ol> {hierarchy.map((item, idx) => ( <TocItem key={idx} item={item} /> ))} </ol> ); }; // 使用示例 // <TableOfContents hierarchy={tocHierarchy} />
这样生成的结构就完全符合你想要的层级关系了,而且后续如果要扩展h4,只需要修改正则和层级判断逻辑就行,扩展性很强。
内容的提问来源于stack exchange,提问作者totalnoob
相关产品推荐
相关产品推荐

