博客目录的改进
2025 年 07 月 01 日 • 关于本站
博客目录存在的一些BUG

之前的博客目录存在一些BUG,如同名标题跳转问题以及正则解析标题可能会将代码块注释也解析成标题。

同名标题跳转问题

这个使用markdown-it-anchor插件在标题渲染成html的时候添加一个唯一id,插件内置唯一id策略当slugify的值相同时候,则返回slugify-{idx}

vue
复制代码
.use(anchor, { slugify: s => s.trim().toLowerCase().replace(/\s+/g, '-') }) // 标题锚点支持

�所以另一边解析目录结构的时候也要配合解析出id

vue
复制代码
const usedIds = new Set() for (const line of lines) { const match = line.match(/^(#{1,6})\s+(.*)/) if (match) { const level = match[1].length const text = match[2].trim() const slug = text.toLowerCase().replace(/\s+/g, '-') let uniqueSlug = slug let i = 1 while (usedIds.has(uniqueSlug)) { uniqueSlug = `${slug}-${i++}` } usedIds.add(uniqueSlug) const node : TocNode = { level, text, id: uniqueSlug, children: [] }

这样之前用textcotent来做MapKey就可以换成id了。

解析标题问题

直接使用markdown-it解析AST,避免正则再去判断#号开头。

vue
复制代码
const md = new MarkdownIt() // 生成 TOC 树结构 const generateTocTree = (markdown : string) : TocNode[] => { const tokens = md.parse(markdown, {}) const toc: TocNode[] = [] const stack: TocNode[] = [] const usedIds = new Set<string>() for (let i = 0; i < tokens.length; i++) { const token = tokens[i] if (token.type === 'heading_open') { const level = parseInt(token.tag.slice(1)) // e.g. 'h2' -> 2 const inlineToken = tokens[i + 1] if (inlineToken && inlineToken.type === 'inline') { const text = inlineToken.content.trim() let slug = text.toLowerCase().replace(/\s+/g, '-') let uniqueSlug = slug let j = 1 while (usedIds.has(uniqueSlug)) { uniqueSlug = `${slug}-${j++}` } usedIds.add(uniqueSlug) const node: TocNode = { level, text, id: uniqueSlug, children: [] } while (stack.length && stack[stack.length - 1].level >= level) { stack.pop() } if (stack.length === 0) { toc.push(node) } else { stack[stack.length - 1].children.push(node) } stack.push(node) } } } return toc }
上一篇
关于本站
博客目录的高亮跟随
星铁3.4开服大歪

留言 (0)

昵称(必填)
邮箱(必填)
网址(选填)