Markdown 目录生成
按标题层级生成目录,锚点遵循 GitHub 规则。代码块和注释里的假标题会被跳过,页面会告诉你跳过了几个。
不勾「输出成链接」时只输出标题文字,适合贴到文档开头当纯文本大纲。序号按层级递增,往深层走时会把更深的计数清零。
结果
这份 HTML 是给不支持自动锚点的静态页面用的:每行都是 h2、h3 这样的标签,标题自带 id,把正文标题换掉或把这段贴到页面顶部,目录里的链接就能直接跳转。
使用说明
目录来自两种标题写法。ATX 是行首一到六个井号加一个空格,## 标题 是二级,井号后面没有空格的行(比如 #话题标签)不算标题;Setext 是标题文字下面跟一行等号或减号,等号是一级、减号是二级,这也是为什么一行 --- 紧跟在一段文字后面时应该按二级标题理解。解析时会先排除列表、引用、缩进代码和围栏行,避免把列表项下面的分隔线误判成标题。
最容易出错的是假标题。围栏代码块里的 #(shell 注释、Python 注释、C 预处理指令)看起来和标题一模一样,本工具会跟踪围栏状态,从 ``` 或 ~~~ 开始到配对的收尾围栏整段跳过;围栏可以带语言名,长度也可以超过三个,收尾必须用同种字符且不短于开头。HTML 注释里的标题同样跳过。结果区那两个「跳过的伪标题」计数就是给这个用的:数字符合预期,才说明解析对了。
锚点按 GitHub 的规则生成:先转成小写,删掉所有标点符号,把空格换成连字符,中文、日文、韩文这类语言文字字符原样保留,下划线和连字符保留。同一个标题重复出现时,第二个追加 -1、第三个追加 -2。这套规则和 VitePress、GitLab 之类并不完全一致——这也是为什么这里额外输出一份带 id 的 HTML:把它复制到自己的静态页面里,锚点就是你看到的那一串,不再受目标站点规则影响。
编号和缩进是可选项。多级序号按层级维护计数器,往深层走时把更深的计数清零,所以一级直接跳到三级会得到 1.0.1,中间的零表示那一级没出现,而不是算错。缩进默认两个空格;四个空格在嵌套很深时容易被某些渲染器当成代码块,Tab 则常被仓库的格式检查拦下。链接选项关掉时只输出标题文字,适合在文档开头放一段纯文本大纲。
全部解析在浏览器本机完成,文档内容不会上传,断网可用。需要先把 HTML 转成 Markdown 再用本工具生成目录,可以用HTML 转 Markdown;反过来要渲染 Markdown 成 HTML 用Markdown 转 HTML;要在编辑器里边写边看效果用Markdown 编辑器;要生成表格用Markdown 表格生成。
常见问题
生成的锚点为什么在别的站点点不动?
因为各家的锚点规则不一样。这里用的是 GitHub 的规则:转小写、删掉标点、空格换连字符、重复标题追加 -1 和 -2。VitePress、hexo、GitLab 对中文和标点的处理细节各有差异,例如有的会把中文标题变成编码后的字符串。要贴到别的静态站点,请用页面下方那份带 id 的 HTML,把 id 一起复制过去就不会失效。
代码块里的 # 会被当成标题吗?
不会。解析时会跟踪围栏状态,``` 或 ~~~ 开头的围栏(可以带 js、bash 这类语言名,围栏长度也可以超过三个反引号)到配对的收尾围栏之间整段跳过。结果区会给出「代码块里跳过的伪标题」条数,这个数字大于 0 就说明解析确实识别到了围栏,可以放心。
为什么我的 YAML 头被算成了标题?
如果文档以 --- 开头,解析器会把到下一个 --- 为止的开头部分当作 front matter 整段跳过,免得结尾那条 --- 被当成 Setext 的二级标题。所以标准的 YAML 头不会产生多余条目;如果开头的 --- 没有配对,那一行就按普通分隔线处理。
同一句话写了两个标题,锚点怎么区分?
从第二次出现开始追加序号。第一个同名标题的锚点是标题本身,第二个变成标题-1,第三个是标题-2,和 GitHub 的处理一致,所以两份目录放进同一个页面也不会互相跳错。
中文标题生成的锚点怎么是一串中文?
这是对的。GitHub 的规则是保留所有语言文字字符,中文、日文、韩文原样留着,只删掉标点符号并把空格换成连字符。所以「快速开始」的锚点就是快速开始,而不是一串百分号编码。这些字符在链接里是合法的,浏览器会自行编码。
Setext 写法(用等号或减号划线)也能识别吗?
能。一整行标题文字下面跟着一行 === 会识别为一级标题,跟着一行 --- 会识别为二级标题。为避免把分隔线误判成标题,会先排除列表、引用、缩进代码和围栏行,只把普通段落行当作候选。
多级序号在缺层级的时候是怎么数的?
按标题层级维护计数器,往深层走时把更深的计数器清零。所以一级下面直接跳到三级标题,会输出 1.0.1 这种带零的编号,而不是硬凑成 1.1.1——零就代表中间那一级没有出现。想避免这种情况,把最大层级调到 2,或者在文档里补齐中间层级。
缩进为什么要分空格和 Tab?
因为 Markdown 渲染器对列表缩进的要求不同。多数用两个空格,四个空格更醒目但容易在嵌套深时被当成代码块,Tab 则是制表符,部分编辑器和 CI 的格式检查会报错。默认两个空格最通用;投稿到强校验的仓库前,先看一眼那边的 .editorconfig。