本页目录
本页目录列出当前页面的标题,读者滚动时高亮正在阅读的那一节。和侧边栏一样,你把标题整理成树,再用 Toc 组件渲染出来。
取出标题
Astro 的 render() 会返回页面的标题列表。在路由文件里把它传给布局:
---
// src/pages/docs/[...slug].astro
const { Content, headings } = await render(Astro.props.entry);
---
<Docs {...Astro.props} headings={headings}>
<Content />
</Docs>
headings 是一个扁平的数组,比如 [{ depth: 2, slug: 'install', text: '安装' }, ...]。
整理成树
tocTree 把扁平的标题列表变成树,h3 放在它前面的 h2 下面:
import { tocTree } from '@minidocs/astro/runtime';
const toc = tocTree(headings);
默认只保留 h2 和 h3。想包含 h4,传入层级范围:tocTree(headings, { depth: [2, 4] })。
渲染
---
import { Toc } from '@minidocs/astro/components';
---
<Toc.Root label="本页目录">
<Toc.List>
{toc.map(function item(heading) {
return (
<Toc.Item>
<Toc.Link slug={heading.slug}>{heading.text}</Toc.Link>
{heading.children.length > 0 && <Toc.List>{heading.children.map(item)}</Toc.List>}
</Toc.Item>
);
})}
</Toc.List>
</Toc.Root>
每个组件的参数见组件与样式。
放在 Layout.Aside 里时,本页目录在中等宽度下会收进一个按钮,见页面布局。
高亮当前小节
读者滚动时,正在阅读的那一节的链接会带上 aria-current="true",默认样式会在它旁边显示一个标记。
一个标题滚过页面顶部的阅读线后,它就是当前小节。阅读线的位置取标题的 scroll-margin-top,也就是点击目录跳转后标题停下的位置,所以跳转和高亮总是一致的。用了 Layout 组件时,默认样式已经设好了这个值。自己写布局并且有固定在顶部的标题栏时,把它设成标题栏的高度:
h2,
h3 {
scroll-margin-top: 4rem;
}
滚到页面底部时,最后一个标题会被高亮,即使它没有到达阅读线。
高亮上级标题
只有当前小节的链接带着 aria-current。想让它的上级标题也换一种样式,用 :has() 选出包含当前项的 <li>:
.md-toc-item:has([aria-current]) > .md-toc-link {
font-weight: 600;
}