如何用JS为无限嵌套独立文档的h1/h2标题添加可复制编号
实现方案
核心思路是使用**深度优先遍历(DFS)**处理DOM结构,每个独立区块维护专属计数器,遇到嵌套子区块时递归处理,处理完成后回到父级继续遍历,完全匹配从上到下的DOM顺序要求。和全局遍历所有标题的方案不同,该方案只遍历当前区块的直接子元素,天然隔离了不同区块的计数边界,不会出现跨区块计数错误的问题。
实现代码
// 移除标题中原有的序号前缀,避免重复添加 function clearOldNumber(text) { return text.replace(/^[\d.\s]+/, ''); } // 处理单个独立区块的标题序号 function processBlock(blockElement) { // 初始化当前区块的独立计数器 let countH1 = 0; let countH2 = 0; let countH3 = 0; // 遍历当前区块的所有直接子元素 for (const el of Array.from(blockElement.children)) { switch(el.tagName) { case 'H1': countH1++; // 高等级标题更新时,重置所有低等级计数器 countH2 = 0; countH3 = 0; el.textContent = `${countH1} ${clearOldNumber(el.textContent)}`; break; case 'H2': countH2++; countH3 = 0; el.textContent = `${countH1}.${countH2} ${clearOldNumber(el.textContent)}`; break; case 'H3': countH3++; el.textContent = `${countH1}.${countH2}.${countH3} ${clearOldNumber(el.textContent)}`; break; default: // 遇到嵌套的独立区块,递归处理 if (el.classList.contains('text_output_expansion')) { processBlock(el); } } } } // 调用入口:先处理最外层根区块 processBlock(document.getElementById('text_output'));
功能说明
- 计数器完全独立:每个
.text_output_expansion区块内部的标题计数不会受外层或其他嵌套区块影响 - 序号可复制:序号直接写入文本节点,复制粘贴文档时会完整保留
- 可扩展:如果需要支持h4~h6等级的标题,只需按现有规则新增对应计数器和判断分支即可
- 适配动态更新:如果区块内容有修改,重新调用
processBlock方法即可刷新序号,不会出现重复叠加序号的问题
内容的提问来源于stack exchange,提问作者user3787031
相关产品推荐
相关产品推荐

