useScroll
跟蹤滾動位置和統計數據
useScroll 追蹤可捲動元素的捲動位置、方向和邊緣到達狀態。它回傳一個物件,包含 x 和 y 位置、isScrolling 狀態、每個方向的 arrivedState(是否到達邊緣)和 directions(捲動方向)。支援節流和偏移量設定。
使用場景
- 建構捲動進度指示器或基於捲動的動畫
- 偵測使用者何時捲動到頂部或底部以顯示/隱藏元素
- 實作根據捲動位置觸發的視差效果
注意事項
- SSR 安全:在伺服器端渲染時位置回傳
0,isScrolling回傳false,到達和方向狀態為預設值。伺服器上不會附加捲動監聽器。 - 節流:使用
throttle選項限制捲動處理器的觸發頻率,以提升複雜捲動式 UI 更新的效能。 - 相關 hooks:另請參閱
useInfiniteScroll用於自動載入更多觸發,useScrollLock用於停用捲動,以及useScrollIntoView用於程式化捲動。
Usage
Live Editor
function Demo() { const elementRef = useRef<HTMLDivElement>(null); const [x, y, isScrolling, arrivedState, directions] = useScroll(elementRef); const { left, right, top, bottom } = useMemo( () => arrivedState, [arrivedState], ); const { left: toLeft, right: toRight, top: toTop, bottom: toBottom, } = useMemo(() => directions, [directions]); const absoluteStyle: CSSProperties = { paddingTop: "0.25rem", paddingBottom: "0.25rem", paddingLeft: "0.5rem", paddingRight: "0.5rem", position: "absolute", }; return ( <div style={{ display: "flex" }}> <div ref={elementRef} style={{ width: 300, height: 300, margin: "auto", borderRadius: "0.25rem", overflow: "scroll", }} > <div style={{ width: 500, height: 400, position: "relative" }}> <div style={{ ...absoluteStyle, top: "0rem", left: "0rem", }} > 左上 </div> <div style={{ ...absoluteStyle, bottom: "0rem", left: "0rem", }} > 左下 </div> <div style={{ ...absoluteStyle, top: "0rem", right: "0rem", }} > 右上 </div> <div style={{ ...absoluteStyle, bottom: "0rem", right: "0rem", }} > 右下 </div> <div style={{ ...absoluteStyle, top: "33.33333%", left: "33.33333%", }} > 滾動我 </div> </div> </div> <div style={{ width: 280, margin: "auto", paddingLeft: "1rem", display: "flex", flexDirection: "column", gap: 5, }} > <div> 位置:{x.toFixed(1)}, {y.toFixed(1)} </div> <div>正在滾動:{JSON.stringify(isScrolling)}</div> <div>到達頂部:{JSON.stringify(top)}</div> <div>到達右側:{JSON.stringify(right)}</div> <div>到達底部:{JSON.stringify(bottom)}</div> <div>到達左側:{JSON.stringify(left)}</div> <div>向上滾動:{JSON.stringify(toTop)}</div> <div>向右滾動:{JSON.stringify(toRight)}</div> <div>向下滾動:{JSON.stringify(toBottom)}</div> <div>向左滾動:{JSON.stringify(toLeft)}</div> </div> </div> ); };
Result
API
useScroll
Returns
readonly [number, number, boolean, UseScrollArrivedState, UseScrollDirection]: 包含以下元素的元組:
- x 值。
- y 值。
- 是否在滚動。
- 到達邊界狀態。
- 滚動方向
Arguments
| 參數名 | 描述 | 類型 | 預設值 |
|---|---|---|---|
| target | dom元素 | BasicTarget<Element> | Document | Window (必填) | - |
| options | 可选参数 | UseScrollOptions | undefined | - |
UseScrollOptions
| 參數名 | 描述 | 類型 | 預設值 |
|---|---|---|---|
| throttle | 滚动事件的节流时间,默认关闭。 | number | 0 |
| idle | 滚动结束时的检查时间。当配置 throttle 时,此配置将设置为 (throttle +idle)。 | number | - |
| offset | 将到达状态偏移 x 像素 | UseScrollOffset | - |
| onScroll | 滚动的回调 | (e: Event) => void | - |
| onStop | 滚动结束的回调 | (e: Event) => void | - |
| eventListenerOptions | 滚动事件参数 | boolean | AddEventListenerOptions | {capture: false, passive: true} |
UseScrollArrivedState
| 參數名 | 描述 | 類型 | 預設值 |
|---|---|---|---|
| left | 到达左边 | boolean (必填) | - |
| right | 到达右边 | boolean (必填) | - |
| top | 到达顶部 | boolean (必填) | - |
| bottom | 到达底部 | boolean (必填) | - |
UseScrollDirection
| 參數名 | 描述 | 類型 | 預設值 |
|---|---|---|---|
| left | 向左滚动 | boolean (必填) | - |
| right | 向右滚动 | boolean (必填) | - |
| top | 向上滚动 | boolean (必填) | - |
| bottom | 向下滚动 | boolean (必填) | - |
BasicTarget
export type BasicTarget<T extends TargetType = Element> = (() => TargetValue<T>) | TargetValue<T> | MutableRefObject<TargetValue<T>>;
TargetValue
type TargetValue<T> = T | undefined | null;
TargetType
type TargetType = HTMLElement | Element | Window | Document | EventTarget;
UseScrollOffset
export interface UseScrollOffset {
left?: number;
right?: number;
top?: number;
bottom?: number;
}