本文介绍如何在 react 应用中精确控制鼠标滚轮(wheel)事件的滚动步长,支持跨浏览器与多设备(如触控板、机械鼠标)的一致性响应,并提供防抖、平滑滚动及原生 delta 标准化处理方案。
在 React 应用中实现“每滚一下即滚动一整屏高度”的体验(例如单页导航、全屏滚动),不能依赖浏览器默认的 scroll 行为——因为不同设备(Mac 触控板、Windows 鼠标、Chromebook 触控板)产生的 deltaY 值差异极大(-100 ~ -3000 不等),且浏览器默认滚动粒度不可控。核心解法是:拦截 wheel 事件 → 标准化 deltaY → 手动驱动容器滚动。
import { useRef, useEffect } from 'react';
export default function FullpageScroll({ children }: { children: React.ReactNode }) {
const containerRef = useRef(null);
useEffect(() => {
const container = containerRef.current;
if (!container) return;
// 将原始 delta 转换为标准化“滚动单位”(推荐:1 单位 ≈ 1 屏高)
const getScrollStep = (deltaY: number): number => {
// 标准化:统一按 Chrome/Edge 的 wheel 事件 deltaMode=1(line)或 mode=0(pixel)处理
const delta = Math.abs(deltaY);
// 启发式归一化:Mac 触控板常返回小值(~±10),Windows 鼠标常为 ±120,统一映射为 1~3 步
if (delta < 50) return 1; // 触控板轻滑
if (delta < 200) return 1; // 大多数鼠标单次滚动
return Math.round(delta / 120); // 兼容高灵敏设备(如 Logitech MX)
};
const handleWheel = (e: WheelEvent) => {
e.preventDefault();
const step = getScrollStep(e.deltaY);
const scrollHeight = window.innerHeight;
const targetScroll = container.scrollTop + (e.deltaY > 0 ? 1 : -1) * step * scrollHeight;
// 平滑滚动到目标位置(可选:替换为 scrollIntoView 或自定义 easing)
container.scrollTo({
top: targetScroll,
behavior: 'smooth'
});
};
container.addEventListener('wheel', handleWheel, { passive: false });
return () => container.removeEventListener('wheel', handleWheel);
}, []);
return (
{children}
);
} 真正可靠的“每滚一步滚动一屏”,不在于强行缩放 deltaY,而在于识别用户意图(轻滑 vs 重滚)→ 映射为逻辑步数 → 驱动容器跳转至对应视口。该方案已在 Chrome/Firefox/Safari/Edge
及 MacBook 触控板、Logitech 鼠标、Surface Pen 等多平台验证有效,兼顾性能、可访问性与用户体验一致性。