minidocs

本页目录

本页目录列出当前页面的标题,读者滚动时高亮正在阅读的那一节。和侧边栏一样,你把标题整理成树,再用 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;
}
本页目录
搜索范围
输入关键词开始搜索