如何为HTML标题元素注入层级编号?JS插件开发疑难
修复HTML标题层级编号JavaScript插件的核心问题
核心问题拆解
要解决的核心逻辑缺陷包括:
- 同级标题未正确递增对应层级编号
- 降级标题未重置后续层级的编号
- 指定部分层级(如H2-H4)时,编号序列混乱
- 缺少自定义起始编号的支持
修正后的完整代码
function generateHeadingNumbers(options = {}) { // 默认配置:处理H1-H6,起始编号全为1 const { selector = 'h1, h2, h3, h4, h5, h6', startNumbers = {} } = options; // 获取所有目标标题并按文档顺序排序 const headings = Array.from(document.querySelectorAll(selector)).sort((a, b) => { return a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1; }); if (!headings.length) return; // 解析目标层级的有序列表(比如H2-H4对应[2,3,4]) const targetLevels = headings.map(el => parseInt(el.tagName.slice(1))).filter((v, i, arr) => arr.indexOf(v) === i).sort((a, b) => a - b); // 初始化编号状态:用自定义起始值填充,未指定的层级默认从1开始 const numberState = {}; targetLevels.forEach(level => { numberState[level] = startNumbers[level] ?? 1; }); let prevLevel = targetLevels[0]; headings.forEach(heading => { const currentLevel = parseInt(heading.tagName.slice(1)); const levelIndex = targetLevels.indexOf(currentLevel); // 处理层级变化:降级时重置后续层级编号 if (currentLevel < prevLevel) { const resetStartIndex = targetLevels.indexOf(prevLevel); for (let i = resetStartIndex; i < targetLevels.length; i++) { const resetLevel = targetLevels[i]; if (resetLevel > currentLevel) { numberState[resetLevel] = startNumbers[resetLevel] ?? 1; } } // 当前层级编号递增 numberState[currentLevel]++; } // 同级标题:当前层级编号递增 else if (currentLevel === prevLevel) { numberState[currentLevel]++; } // 升级标题:直接使用初始值(或已存在的状态) else { // 若升级层级未初始化,用起始值或1 if (!numberState[currentLevel]) { numberState[currentLevel] = startNumbers[currentLevel] ?? 1; } } // 生成完整编号字符串:只包含目标层级的编号 const numberParts = targetLevels .filter(level => level <= currentLevel) .map(level => numberState[level]); const numberStr = numberParts.join('.') + ' '; // 注入编号:避免重复注入,先清除已有编号 const existingNumber = heading.firstChild?.nodeType === Node.TEXT_NODE && heading.firstChild.textContent.match(/^\d+(\.\d+)* /); if (existingNumber) { heading.firstChild.textContent = heading.firstChild.textContent.replace(existingNumber[0], ''); } heading.insertBefore(document.createTextNode(numberStr), heading.firstChild); prevLevel = currentLevel; }); } // 使用示例 // 1. 处理H2-H4,H2从2开始,H3从0开始 generateHeadingNumbers({ selector: 'h2, h3, h4', startNumbers: { 2: 2, 3: 0 } }); // 2. 默认处理所有标题,起始编号全为1 generateHeadingNumbers();
关键逻辑说明
- 目标层级解析:自动提取指定选择器对应的标题层级并排序,确保只处理用户关注的层级
- 编号状态维护:用对象存储每个层级的当前编号,降级时自动重置后续层级的编号为初始值
- 重复注入防护:每次注入前检查并清除已有的编号,避免重复添加
- 自定义起始值支持:通过
startNumbers参数灵活指定任意层级的起始编号,未指定的层级默认从1开始 - 文档顺序保证:使用
compareDocumentPosition确保标题按页面中的实际顺序处理,避免DOM选择器顺序异常
内容的提问来源于stack exchange,提问作者markb
相关产品推荐
相关产品推荐

