Hexo 里的标题锚点链接
名词解释
标题:即 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 | ## example |
其中第一个 heading 的 id 是 example
,那么第二个就应该是 example-1
,第三个跟第二个冲突了,现在版本(0.3.2)的 hrm 对这个问题并没有做任何处理。
第二个问题是当我的 heading 的文字是中文(或者其他非英文字符)时,hash id 在 URL 里可能会被转码而变得很长,或者就是我想要 heading 的文字和 anchor 的 id 不一样。这个需求现在的 hrm 也没法做到。
解决方案
所以我 fork 了 hrm,然后把这两个问题都解决了:https://github.com/mdluo/hexo-renderer-marked ,写了完整的测试用例(我修改的部分测试覆盖100%)和相应的文档。修改的内容可以参考下面这个 PR 链接。
稍后我会提交一个 PR 到原版 hrm 已经提交 PR,但是合并之前可以先通过
1 | yarn add https://github.com/mdluo/hexo-renderer-marked |
来使用。
使用方法
在 _config.yml
里添加一项配置
1 | marked: |
然后在 markdown 里用类似下面的格式就可以了,id 重复(包括链接作为 id 的) 的问题已经解决,不管是否开启此项都会生效。
1 | ## [插件](#the-plugin) |
如果生成的网页没有变化,可以试一下 hexo clean
来清除缓存重新编译。
另外,为了使网页定位到某个 anchor 的时候在上方稍微留出点空间,可以设置一下 padding 和 margin。以及为了让 heading 有个交互的效果可以加个 ::before
伪元素。具体效果可以参考本文。
1 | h1, h2, h3, h4, h5, h6 { |
有其他任何问题欢迎到 PR 里讨论或者在本文下留言。