Page Transition
路由過場容器,結合 View Transitions 觀念與覆蓋揭示,於路由改變時播放淡入、滑動、覆蓋或抹除四款過場。
載入預覽⋯
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
0.6
24
<PageTransition />
安裝
npx shadcn@latest add https://webberui.com/r/page-transition.json或在 components.json 設定 registries 後,改用 @webberui/page-transition 安裝。
安裝依賴後,從 registry JSON(/r/page-transition.json 的 files[0].content)複製 page-transition.tsx 原始碼到你的 components/ui/ 目錄:
npm install motion clsx tailwind-merge使用
把頁面內容包進 PageTransition,並將會隨路由改變的值(通常是 pathname)傳給 transitionKey。在 Next.js App Router 中,最自然的位置是 template.tsx:
"use client";
import { usePathname } from "next/navigation";
import { PageTransition } from "@/components/ui/page-transition";
export default function Template({ children }: { children: React.ReactNode }) {
const pathname = usePathname();
return (
<PageTransition transitionKey={pathname} variant="cover" direction="right">
{children}
</PageTransition>
);
}原生 View Transitions
若想在導覽時觸發瀏覽器原生的 View Transitions(跨頁交叉淡入、共享元素 morph),可用 useViewTransition 包住會改變 DOM 的更新:
"use client";
import { useRouter } from "next/navigation";
import { useViewTransition } from "@/components/ui/page-transition";
export function NavLink({ href, children }: { href: string; children: React.ReactNode }) {
const router = useRouter();
const startTransition = useViewTransition();
return (
<a
href={href}
onClick={(event) => {
event.preventDefault();
startTransition(() => router.push(href));
}}
>
{children}
</a>
);
}不支援 View Transitions 的瀏覽器會直接執行更新,行為優雅降級。
Props
PageTransition
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
children | React.ReactNode | — | 頁面內容 |
transitionKey | string | number | — | 過場觸發鍵,改變即播放一次過場(通常傳 pathname) |
variant | "fade" | "slide" | "cover" | "wipe" | "fade" | 過場款式 |
direction | "up" | "down" | "left" | "right" | "up" | 位移/覆蓋掃動的方向 |
duration | number | 0.6 | 整段過場的總時長(秒),出場與進場各半 |
distance | number | 24 | slide 款式的位移距離(px) |
overlayClassName | string | — | 覆蓋層(cover/wipe)的追加 className,可覆寫底色 |
className | string | — | 追加到外層容器的 className |
onTransitionComplete | () => void | — | 過場完整結束時的回呼 |
useViewTransition()
回傳 startTransition(update),update 為會改變 DOM 的函式(可為同步或回傳 Promise),回傳解析於過場結束的 Promise<void>。
細節
- 狀態機驅動:內部以「出場 → 於覆蓋高峰無縫替換內容 → 進場」三段狀態機運作,全程僅靠 Motion 的
onAnimationComplete推進,不使用任何計時器。 - 覆蓋揭示:
cover以實心面板滑入覆蓋、由反側滑出揭示;wipe以沿軸線縮放的方式抹過,覆蓋與揭示自動切換transform-origin。內容替換發生在面板完全覆蓋的瞬間,肉眼看不到跳動。 - 首次載入不動畫:初次渲染與 SSR 輸出一致,只有在
transitionKey改變後才播放過場。 - 快速連續切換:過場進行中再次改變
transitionKey,會在當前過場結束後直接跳到最新內容,不會堆疊播放。
可及性
- 使用者系統開啟「減少動態效果」時,內容直接即時替換,不播放任何位移或覆蓋動畫。
- 過場進行中外層容器帶
aria-busy,覆蓋層以aria-hidden對輔助科技隱藏、且pointer-events-none不攔截操作。