输入 · 14
滚轮分档
Wheel stepper · wheel-stepper把一串滚轮事件识别为一次翻页,累积到阈值后只前进一档。
触控板轻扫会接连发出事件,松手后还有惯性尾巴。每次事件都翻页会一口气越过数张;只加大阈值又让鼠标滚轮迟钝。累计、锁定和安静后解锁把这些事件变成一次意图。
公式
acc += deltaPx if |acc| ≥ threshold and !locked: step(sign(acc)) locked ← true until quiet or new flick
参数
| 本页默认 | 成熟实现 | |
|---|---|---|
| threshold | 40 px | motion-kit 40 px |
| quietMs | 180 ms | motion-kit 180 ms |
| spike | 1.8× | motion-kit 1.8× |
怎样做好
- 先累积再分档。motion-kit 的滚轮分档器用 40 px 阈值,触发后锁住事件流。www-motion/rewrite/lib/motion-kit.js:392–415
- 安静 180 ms 才结束手势;新事件突然放大 1.8 倍时可提早识别下一次甩动。www-motion/rewrite/lib/motion-kit.js:392–415
- 真实 motion-kit 还允许持续滚动 950 ms 后再前进,但要求当前幅度仍接近峰值,以免把惯性尾巴当成按住。www-motion/rewrite/lib/motion-kit.js:385–405
在我们的案例里
11 个案例使用滚轮分档,另有 8 个使用滑动阈值;合并后是 14 个案例。iris、cinema-reel 和 dimension 同时涉及两者,说明“是否切换一页”要统一判定。
出现在 14 个案例
参考实现 · basics.js
/**
* One gesture = one step. Accumulate wheel delta until `threshold`, step, then stay locked
* until the stream has been quiet for `quietMs` (trackpad inertia tails keep firing for ~1 s).
* A sudden bigger event (`spike` × the last one) is a new flick and unlocks early.
*/
export function createWheelStepper(onStep, { threshold = 40, quietMs = 180, spike = 1.8 } = {}) {
let acc = 0, locked = false, last = 0, lastMag = 0, timer = 0;
return (delta, now = performance.now()) => {
const mag = Math.abs(delta);
if (locked && mag > lastMag * spike && mag > 8) locked = false;
lastMag = mag; last = now;
clearTimeout(timer);
timer = setTimeout(() => { locked = false; acc = 0; }, quietMs);
if (locked) return;
acc += delta;
if (Math.abs(acc) >= threshold) { onStep(Math.sign(acc)); acc = 0; locked = true; }
};
}