輪播
速度銜接場景滑軌
以拖曳初速銜接切換的場景卡滑軌:放手時的速度直接成為下一張的彈簧初速,底部膠囊指示條隨進度伸縮。
一條水平場景軌道:每張場景卡可放任意內容,左右拖曳或點底部指示條切換。重點在放手的那一刻——拖曳速度會原封交給換頁彈簧當初速,快甩就快速到位,慢推就緩緩滑過去,動作從手指到落定是一條連續的速度曲線。拖曳中底部膠囊指示條依進度一伸一縮,場景卡越靠近中央越清楚。適合功能導覽、新手引導、產品場景展示。
把這個效果裝進你的專案
在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。
npx webberui@latest add "https://webberui.com/r/velocity-scene-slider.json?t=<安裝 token>"Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
260
30
400
編輯中的呼叫預設屬性
<VelocitySceneSlider/>
完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。
安裝
npx webberui@latest add "https://webberui.com/r/velocity-scene-slider.json?t=<安裝 token>"或在 components.json 設定 registries 後,改用 @webberui/velocity-scene-slider 安裝。
使用
import {
VelocitySceneSlider,
type VelocityScene,
} from "@/components/ui/velocity-scene-slider";
const scenes: VelocityScene[] = [
{ id: "inbox", label: "收件匣整理", content: <InboxScene /> },
{ id: "schedule", label: "排程建議", content: <ScheduleScene /> },
{ id: "board", label: "團隊看板", content: <BoardScene /> },
];
export function Tour() {
const [index, setIndex] = React.useState(0);
return (
<VelocitySceneSlider
scenes={scenes}
index={index}
onIndexChange={setIndex}
onRelease={({ velocity }) => console.log(`${Math.round(velocity)} px/s`)}
/>
);
}Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
scenes | VelocityScene[] | — | 場景卡清單,建議 3–7 張 |
index | number | — | 受控模式的目前場景索引;未提供時由元件內部管理 |
defaultIndex | number | 0 | 非受控模式的初始場景索引 |
onIndexChange | (index: number) => void | — | 場景切換時回呼(拖曳、指示條、鍵盤皆會回報) |
onRelease | (info: VelocitySceneRelease) => void | — | 拖曳放手時回呼,帶放手速度、位移與目標索引 |
stiffness | number | 260 | 換頁彈簧剛性,越高越快到位 |
damping | number | 30 | 換頁彈簧阻尼,越低越容易回彈過頭 |
velocityThreshold | number | 400 | 放手速度超過此值(px/s)即換頁,不論位移多寡 |
loop | boolean | false | 到頭/到尾時是否環繞至另一端 |
showIndicator | boolean | true | 是否顯示底部膠囊指示條 |
ariaLabel | string | "場景輪播" | 整個輪播區域的無障礙標籤 |
className | string | — | 透傳到最外層容器 |
VelocityScene
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
id | string | — | 場景唯一識別碼 |
label | string | — | 場景名稱,用於指示條按鈕與螢幕閱讀器朗讀 |
content | React.ReactNode | — | 場景卡內容 |
VelocitySceneRelease
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
velocity | number | — | 放手當下的水平速度(px/s,向左為負) |
offset | number | — | 拖曳期間的水平位移(px) |
index | number | — | 放手後要前往的場景索引 |
CSS 變數
| 變數 | 預設值 | 說明 |
|---|---|---|
--wb-velocity-scene-indicator-duration | 240ms | 指示條膠囊寬度與顏色的過渡時間 |
--wb-velocity-scene-gap | 24px | 場景卡之間的間距;步距會從實際版面量測,覆寫後拖曳與定位自動跟上 |
細節
- 速度銜接:放手時讀取拖曳速度,原封交給換頁彈簧的
velocity。同樣的stiffness/damping,快甩與慢推的到位時間與手感因此不同;點指示條或用鍵盤換頁時初速為 0 - 換頁判定:速度優先——放手速度絕對值超過
velocityThreshold就往速度方向換一頁;否則位移超過卡寬 25% 才換頁,未達則彈回原位 - 環繞:
loop開啟時從最後一張往後甩會回到第一張。這時軌道要往反方向長距離移動,沿用放手速度會先朝錯的方向衝出去,所以環繞時初速改為 0 - 指示條:平時作用中的膠囊 28px、其餘 8px,以 CSS 過渡伸縮;拖曳中改依連續進度逐幀插值相鄰兩顆的寬度,呈現被拉長的感覺
- 場景卡:依與中央的距離插值,縮放 0.94→1、透明度 0.6→1;卡寬為容器的 82%,左右露出鄰卡一角
- 受控模式:父層若不接受
onIndexChange回報的新索引,軌道會以彈簧回到原本的場景
可及性
- 根元素為
role="region"、aria-roledescription="carousel",可用 Tab 聚焦,帶focus-visible外框 - 每張場景卡為
role="group"、aria-roledescription="slide",aria-label為「第 n 張,共 N 張:名稱」;不在中央的卡片設為inert,不可聚焦也不會被朗讀 - 聚焦後可用左右方向鍵換頁,Home/End 跳到第一張/最後一張
- 指示條為
role="tablist",每顆膠囊是帶aria-selected與aria-controls的type="button"分頁按鈕,採 roving tabindex,方向鍵移動時焦點跟著走 - 以
aria-live="polite"宣告目前場景 - 使用者系統開啟「減少動態效果」時,停用拖曳放手後的彈簧慣性,換頁改為合計 150ms 的淡出淡入;指示條膠囊直接跳到目標寬度,不做過渡