Hexo 里的标题锚点链接

Feb 11, 2018 hexo, html

名词解释

  • 标题:即 heading,在 Markdown 里是从 #######,对应 HTML 里从 <h1><h6>。下面用 #[n]<hn>(n: 1-6 ) 来表示;

  • 锚点:即 anchor,anchor 会同时作为锚点要定位到的元素的 id,以及链接 URL 最后的 # 之后的部分。

  • 链接:很多网页都支持点击标题自动在 URL 后面加上 #anchor,这样方便浏览者把当前文档部分通过 URL 分享出去,尤其是当网页内容特别多的时候这个功能特别实用。本文也已经实现。

插件

Hexo 的 Markdown 渲染默认是用的 hexo-renderer-marked(以下简称 hrm),实际的 Markdown 到 HTML 的转换是 marked 完成的,hrm 作为插件对其中一些元素的渲染做了调整。

hrm 对于标题(即 heading,Markdown 里是从 #######,对应 HTML 里从 <h1><h6>)做了特殊处理,会给输出的 <hn>(n 表示 1-6 ) 元素加上 id 属性,以及一个内部的 <a> 元素。这里的 id 的值是根据 heading 的内容,删除首尾多余空格,如果是中间有空格用连字符连接而得来。如果 id 有重复的值,会在第二个 id 的后面加上 -1,如果还继续重复就变成 -2、-3 …

问题

hrm 对于重复的 id 考虑的不是很周到,考虑这种情况:

1
2
3
## example
## example
## example-1

其中第一个 heading 的 id 是 example,那么第二个就应该是 example-1,第三个跟第二个冲突了,现在版本(0.3.2)的 hrm 对这个问题并没有做任何处理。

第二个问题是当我的 heading 的文字是中文(或者其他非英文字符),或者就是我想要 heading 的文字和 anchor 的 id 不一样。这个需求现在的 hrm 也没法做到。

解决方案

所以我 fork 了 hrm,然后把这两个问题都解决了:https://github.com/mdluo/hexo-renderer-marked ,写了完整的测试用例和相应的文档。修改的内容可以参考 https://git.io/vAttJ

稍后我会提交一个 PR 到原版 hrm,但是合并之前可以先通过

1
yarn add https://github.com/mdluo/hexo-renderer-marked

来使用。

使用方法

_config.yml 里添加一项配置

1
2
marked:
anchorAlias: true

然后在 markdown 里用类似下面的格式就可以了,id 重复(包括链接作为 id 的) 的问题已经解决,不管是否开启此项都会生效。

1
2
3
## [插件](#the-plugin)
## [问题](#problem)
## [使用方法](#usage)

如果生成的网页没有变化,可以试一下 hexo clean 来清除缓存重新编译。

另外,为了使网页定位到某个 anchor 的时候在上方稍微留出点空间,可以设置一下 padding 和 margin。以及为了让 heading 有个交互的效果可以加个 ::before 伪元素。具体效果可以参考本文。

1
2
3
4
5
6
7
8
9
10
11
h1, h2, h3, h4, h5, h6 {
padding-top: 1em;
margin-top: -1em;
&:hover {
&::before {
content: '#';
margin-left: -0.8em;
position: absolute;
}
}
}