Interactive Dot Grid
互動點陣背景:滿版規則點陣,游標附近的點放大並被斥力推開,離開後平滑回位。
載入預覽⋯
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
28
1.5
120
<InteractiveDotGrid />
安裝
npx shadcn@latest add https://webberui.com/r/interactive-dot-grid.json或在 components.json 設定 registries 後,改用 @webberui/interactive-dot-grid 安裝。
安裝依賴後,打開 interactive-dot-grid.json,把 files[0].content 的內容複製到你的 components/ui/interactive-dot-grid.tsx:
npm install motion clsx tailwind-merge使用
元件會填滿具尺寸的父層,前景內容以絕對定位疊在其上;讓覆蓋層帶 pointer-events-none,游標事件才會落到點陣上:
import { InteractiveDotGrid } from "@/components/ui/interactive-dot-grid";
<div className="relative h-[400px] overflow-hidden rounded-2xl">
<InteractiveDotGrid />
<div className="pointer-events-none absolute inset-0 flex items-center justify-center">
<h2 className="text-2xl font-semibold">移動游標看點陣互動</h2>
</div>
</div>調整密度、影響範圍與顏色:
<InteractiveDotGrid gap={36} dotRadius={2} influence={160} color="#38bdf8" />Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
gap | number | 28 | 點與點的間距(px),同時決定點的密度 |
dotRadius | number | 1.5 | 靜止時每個點的半徑(px) |
influence | number | 120 | 游標影響半徑(px):此範圍內的點才會放大並被推開 |
color | string | 淺色 neutral-400 / 深色 neutral-600 | 點的顏色;未指定時隨主題切換 |
className | string | — | 附加到最外層容器的 class |
細節
- 單一 canvas 繪製。 整個點陣畫在一張
<canvas>上,ResizeObserver取容器尺寸並依devicePixelRatio(上限 2×)調整背景緩衝區,避免高解析度螢幕模糊 - 斥力越近越強。 每幀對每個點計算與游標的距離,落在
influence內時取1 - dist / influence為強度,據此沿反向推開(最多約influence的 35%)並放大半徑 - 平滑回位。 游標座標與整體影響強度都以插值追隨目標,游標離開容器後強度衰減回 0,點陣自然回到基準位置
- 閒置省能。 動畫靜止且點陣回到基準後,rAF 迴圈只保留輕量插值計算而略過繪製,游標再次進入時自動喚醒
- 顏色隨主題。 未指定
color時,canvas 以currentColor(text-neutral-400 dark:text-neutral-600)取色,並用MutationObserver監看<html>的 class 變化,深淺主題切換即時重繪 - 只有滑鼠指標(
pointerType === "mouse")會觸發互動,觸控不作用
可及性
- 點陣為純裝飾背景,最外層帶
aria-hidden,不干擾輔助科技朗讀前景內容 - 使用者系統開啟「減少動態效果」時,只繪製靜態點陣、不啟動動畫迴圈、不回應游標
- 元件卸載時清理 rAF、
ResizeObserver與MutationObserver,不留下背景計時器