PC05▸🧭 Navigation · 導航▸目錄
Scrollspy
滾動目錄
難度 ★★★★★標籤 scrollspy · IO · 目錄3 min read
模式簡述
Scrollspy:長文章右側目錄自動高亮當前段落。文件站、blog 必備。用 IntersectionObserver 實作。
前言
假內容假內容假內容⋯
安裝
假內容假內容假內容⋯
API
假內容假內容假內容⋯
進階
假內容假內容假內容⋯
FAQ
假內容假內容假內容⋯
Claude Code Prompt
參考:PC05 scrollspy 組件:Scrollspy.tsx Scrollspy:長文章右側目錄自動高亮當前段落。文件站、blog 必備。用 IntersectionObserver 實作。 限制: - IO threshold 設錯 - 多個 section 同時可見 - 忘了平滑捲動
完整程式碼
"use client";
import { useEffect, useState } from "react";
import { cn } from "@/lib/utils";
type State = "top" | "middle" | "bottom";
const SECTIONS = ["前言", "安裝", "API", "進階", "FAQ"];
export function Scrollspy({ state = "top" }: { state?: State }) {
const activeIdx = state === "top" ? 0 : state === "middle" ? 2 : SECTIONS.length - 1;
const [active, setActive] = useState(activeIdx);
useEffect(() => setActive(activeIdx), [activeIdx]);
return (
<div className="grid w-full max-w-md grid-cols-[140px_1fr] gap-4">
<aside className="space-y-0.5 self-start border-l border-border pl-3">
{SECTIONS.map((s, i) => (
<button
key={s}
onClick={() => setActive(i)}
className={cn(
"block w-full text-left text-xs transition",
i === active
? "border-l-2 border-lab-accent -ml-[13px] pl-3 text-lab-accent"
: "text-muted-foreground hover:text-foreground",
)}
>
{s}
</button>
))}
</aside>
<div className="space-y-3 rounded-lg border border-border bg-background/30 p-3">
{SECTIONS.map((s, i) => (
<div
key={s}
className={cn(
"rounded-md px-3 py-2 text-xs transition",
i === active ? "bg-lab-accent/10 ring-1 ring-lab-accent/30" : "bg-background/40",
)}
>
<p className="font-medium text-foreground">{s}</p>
<p className="mt-1 text-muted-foreground">假內容假內容假內容⋯</p>
</div>
))}
</div>
</div>
);
}何時用
- ✅ 長篇文件、API reference
- ✅ 技術 blog 文章
- ✅ 教學內容章節導航
何時別用
- ❌ 短文章 < 3 段(沒必要)
- ❌ 純圖片或非文字內容
- ❌ 手機端(沒空間放側欄)
我踩過的坑
-
IO threshold 設錯:0 會在剛進視口就觸發,0.5 才合理。
-
多個 section 同時可見:取最頂部那個為 active,不是隨便挑一個。
-
忘了平滑捲動:點目錄要 smooth scroll 而不是瞬間跳。css scroll-behavior: smooth。
相關模式
- PC02
- PC04