603 字
3 分钟
Fuwari 博客改造计划:为侧边栏添加 Sticky 文章目录

为什么需要侧边栏目录?#

Fuwari 原生的目录索引仅在 2K 屏幕以上可见。对于大多数 1080P 或更小屏幕的用户,阅读长文章时缺乏导航。此外,在阅读文章时,顶部的头像卡片(Profile)信息冗余。通过“动态替代”方案,我们可以在阅读时将头像换成目录,并让它始终固定在侧边栏顶部。

设计架构#

为了实现平滑的切换和高效的导航,我们采用了容器替换 + 路由感知的设计模式:

1. 动态路由感知 (Route Awareness)#

在侧边栏组件中注入当前路径判断逻辑。只有当路径匹配 /posts/ 且文章包含标题数据(Headings)时,才会激活目录显示。

2. 局部容器替换 (Partial Hydration & Swup)#

利用 Swup 的局部容器更新特性,将侧边栏顶部划分为独立容器 #sidebar-top

  • 首页/归档页:渲染 Profile 组件。
  • 文章页:渲染 SideBarTOC 组件。 Swup 会在页面跳转时精准替换此区域,实现“移花接木”的效果。

3. 粘性布局 (Sticky Strategy)#

将目录组件放入侧边栏的 sticky 区域。通过隐藏非 Sticky 的头像卡片,目录卡片会自动上移至侧边栏的最顶端,并在滚动时始终锁定在视口内。


核心实现步骤#

1. 创建 SideBarTOC.astro#

创建 src/components/widget/SideBarTOC.astro。为保持简洁,我们仅提取一级标题展示。

---
import type { MarkdownHeading } from "astro";
import { siteConfig } from "../../config";
import { url } from "../../utils/url-utils";
interface Props {
class?: string;
headings: MarkdownHeading[];
}
let { headings = [] } = Astro.props;
let minDepth = Math.min(...headings.map(h => h.depth), 10);
---
<div class:list={["card-base p-4", Astro.props.class]}>
<div class="font-bold transition text-lg text-neutral-900 dark:text-neutral-100 relative ml-4 mb-2
before:w-1 before:h-4 before:rounded-md before:bg-[var(--primary)]
before:absolute before:left-[-16px] before:top-[5.5px]">
目录
</div>
<div class="max-h-[70vh] overflow-y-auto hide-scrollbar">
{headings.filter(h => h.depth === minDepth).map((heading, idx) => (
<a href={`#${heading.slug}`} class="px-2 flex gap-2 relative transition w-full py-2 hover:bg-[var(--toc-btn-hover)] rounded-xl">
<div class="bg-[var(--toc-badge-bg)] text-[var(--btn-content)] w-5 h-5 shrink-0 rounded-lg text-xs flex items-center justify-center font-bold">
{idx + 1}
</div>
<div class="text-sm text-50">{heading.text.replace(/#$/, '')}</div>
</a>
))}
</div>
</div>

2. 集成到 SideBar#

修改 src/components/widget/SideBar.astro,实现组件切换。

<div id="sidebar">
<div id="sidebar-top" class="transition-swup-fade mb-4">
{!isPostsRoute && <Profile />}
</div>
<div id="sidebar-sticky" class="sticky top-4">
<div id="sidebar-toc" class="transition-swup-fade">
{isPostsRoute && <SideBarTOC headings={headings} />}
</div>
<Categories />
<!-- ... 其他小组件 -->
</div>
</div>

3. 配置 Swup 容器#

astro.config.mjs 中,将新定义的 ID 加入更新列表:

containers: ["main", "#toc", "#sidebar-top", "#sidebar-toc"]

结语#

这种方案不仅不占额外的屏幕空间,还极大提升了长文阅读的导航便利性,是针对侧边栏空间的二次利用。

Fuwari 博客改造计划:为侧边栏添加 Sticky 文章目录
https://fuwari.vercel.app/posts/fuwari博客改造计划在侧边栏添加文章目录索引/
作者
Watch Your Back
发布于
2026-04-05
许可协议
CC BY-NC-SA 4.0