原文链接:https://ssshooter.com/2019-01...
前面说过基本功能已经添加完了,但是生成目录依然是我 TODO 的头号问题。今天终于把这个问题解决了,本来以为要自己解释 md 文件,没想到自带的插件就有这个功能我却没发现。
生成目录
获取目录数据
生成目录首先要获取目录数据,此功能由插件 gatsby-transformer-remark
提供,请务必先安装。
安装后在你需要获取目录的页面的 graphQL 查询代码中添加 tableOfContents
。tableOfContents
后面的 pathToSlugField 用于生成锚点链接地址,默认值为当前文章的 slug
。在例子中就把地址的前缀改成 md 文件提供的 path 了。这个位置就看你本来的地址怎么配置,如果本来就是 slug 则不用修改,直接写 tableOfContents 不用后面括号的部分。(不过我在实践中发现改了之后地址也不会变,原因未明,谷歌也搜索不到类似的情况)
{
markdownRemark(fields: { slug: { eq: $slug } }) {
id
excerpt
html
tableOfContents(pathToSlugField: "frontmatter.path")
frontmatter {
title
tags
date(formatString: "MMMM DD, YYYY")
}
}
}
接着你就能得到像这样的目录字符串:
""
参考链接:https://www.gatsbyjs.org/pack...
注入锚点
你可能觉得上面的字符串塞到网页就大功告成……嗯我当时也这么想。
现在你即使有这么一个带 url 的目录,点击缺不会跳转到对应位置。因为 markdown 转换到 html 之后并没有注入锚点。为解决这个问题要引入一个新插件 gatsby-remark-autolink-headers。
npm install --save gatsby-remark-autolink-headers
安装后进行如下配置
// In your gatsby-config.js
module.exports = {
plugins: [
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [`gatsby-remark-autolink-headers`],
},
},
],
}
如果是看过之前的教程的话一定知道我的事例项目用了 prismjs,prismjs 插件与 autolink 有迷之冲突,一定要把 autolink 放前,prismjs 放后:
// good
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
`gatsby-remark-autolink-headers`,
`gatsby-remark-prismjs`,
],
},
}
// bad
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
`gatsby-remark-prismjs`, // should be placed after `gatsby-remark-autolink-headers`
`gatsby-remark-autolink-headers`,
],
},
}
添加成功后由 md 文件转换得到的 html 字符串里的标题就会都带上 id,这样锚链接就能正常使用啦!
参考链接:https://www.gatsbyjs.org/pack...
调整样式
以下是我的样式代码,因为框架的全局样式对 ul 和 li 的影响挺大的,所以不少代码是用于修复的。另外是用媒体查询在大屏时把目录固定到左下角。
.css-toc {
color: $titleColor;
padding: 15px;
background: #fcfaf2;
margin-bottom: 25px;
> ul {
padding-left: 16px;
}
ul {
list-style-type: square;
list-style-position: outside;
margin-bottom: 0;
p {
vertical-align: top;
display: inline-block;
}
}
li {
margin-bottom: 0;
}
li > p {
margin-bottom: 0;
}
li > ul {
margin-top: 0;
}
}
@media screen and (min-width: 1045px) {
.css-toc {
position: fixed;
bottom: 0;
right: 0;
width: 200px;
max-height: 400px;
overflow: scroll;
font-size: 14px;
li > ul {
margin-left: 1rem;
}
}
}