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博客改造计划在侧边栏添加文章目录索引/