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

參數名描述類型預設值
targetdom元素BasicTarget<Element> | Document | Window (必填)-
options可選參數UseScrollOptions | undefined-

UseScrollOptions

參數名描述類型預設值
throttle滚動事件的節流時間,預設關閉。number0
idle滚動結束時的檢查時間。當配置 throttle 時,此配置將設置為 (throttle +idle)。number200
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;
}