Throttle scroll events
This commit is contained in:
parent
df393ae959
commit
d8ceb03d74
1 changed files with 54 additions and 50 deletions
|
@ -1,4 +1,5 @@
|
||||||
import { useEffect, useLayoutEffect, useState } from 'preact/hooks';
|
import { useEffect, useLayoutEffect, useRef, useState } from 'preact/hooks';
|
||||||
|
import { useThrottledCallback } from 'use-debounce';
|
||||||
|
|
||||||
export default function useScrollFn(
|
export default function useScrollFn(
|
||||||
{
|
{
|
||||||
|
@ -22,59 +23,62 @@ export default function useScrollFn(
|
||||||
const [nearReachStart, setNearReachStart] = useState(false);
|
const [nearReachStart, setNearReachStart] = useState(false);
|
||||||
const [nearReachEnd, setNearReachEnd] = useState(false);
|
const [nearReachEnd, setNearReachEnd] = useState(false);
|
||||||
const isVertical = direction === 'vertical';
|
const isVertical = direction === 'vertical';
|
||||||
|
const previousScrollStart = useRef(null);
|
||||||
|
|
||||||
|
const onScroll = useThrottledCallback(() => {
|
||||||
|
const scrollableElement = scrollableRef.current;
|
||||||
|
const {
|
||||||
|
scrollTop,
|
||||||
|
scrollLeft,
|
||||||
|
scrollHeight,
|
||||||
|
scrollWidth,
|
||||||
|
clientHeight,
|
||||||
|
clientWidth,
|
||||||
|
} = scrollableElement;
|
||||||
|
const scrollStart = isVertical ? scrollTop : scrollLeft;
|
||||||
|
const scrollDimension = isVertical ? scrollHeight : scrollWidth;
|
||||||
|
const clientDimension = isVertical ? clientHeight : clientWidth;
|
||||||
|
const scrollDistance = Math.abs(scrollStart - previousScrollStart.current);
|
||||||
|
const distanceFromStartPx =
|
||||||
|
_distanceFromStartPx ||
|
||||||
|
Math.min(
|
||||||
|
clientDimension * distanceFromStart,
|
||||||
|
scrollDimension,
|
||||||
|
scrollStart,
|
||||||
|
);
|
||||||
|
const distanceFromEndPx =
|
||||||
|
_distanceFromEndPx ||
|
||||||
|
Math.min(
|
||||||
|
clientDimension * distanceFromEnd,
|
||||||
|
scrollDimension,
|
||||||
|
scrollDimension - scrollStart - clientDimension,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
scrollDistance >=
|
||||||
|
(previousScrollStart.current < scrollStart
|
||||||
|
? scrollThresholdEnd
|
||||||
|
: scrollThresholdStart)
|
||||||
|
) {
|
||||||
|
setScrollDirection(
|
||||||
|
previousScrollStart.current < scrollStart ? 'end' : 'start',
|
||||||
|
);
|
||||||
|
previousScrollStart.current = scrollStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
setReachStart(scrollStart <= 0);
|
||||||
|
setReachEnd(scrollStart + clientDimension >= scrollDimension);
|
||||||
|
setNearReachStart(scrollStart <= distanceFromStartPx);
|
||||||
|
setNearReachEnd(
|
||||||
|
scrollStart + clientDimension >= scrollDimension - distanceFromEndPx,
|
||||||
|
);
|
||||||
|
}, 500);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const scrollableElement = scrollableRef.current;
|
const scrollableElement = scrollableRef.current;
|
||||||
if (!scrollableElement) return {};
|
if (!scrollableElement) return {};
|
||||||
let previousScrollStart = isVertical
|
previousScrollStart.current =
|
||||||
? scrollableElement.scrollTop
|
scrollableElement[isVertical ? 'scrollTop' : 'scrollLeft'];
|
||||||
: scrollableElement.scrollLeft;
|
|
||||||
|
|
||||||
function onScroll() {
|
|
||||||
const {
|
|
||||||
scrollTop,
|
|
||||||
scrollLeft,
|
|
||||||
scrollHeight,
|
|
||||||
scrollWidth,
|
|
||||||
clientHeight,
|
|
||||||
clientWidth,
|
|
||||||
} = scrollableElement;
|
|
||||||
const scrollStart = isVertical ? scrollTop : scrollLeft;
|
|
||||||
const scrollDimension = isVertical ? scrollHeight : scrollWidth;
|
|
||||||
const clientDimension = isVertical ? clientHeight : clientWidth;
|
|
||||||
const scrollDistance = Math.abs(scrollStart - previousScrollStart);
|
|
||||||
const distanceFromStartPx =
|
|
||||||
_distanceFromStartPx ||
|
|
||||||
Math.min(
|
|
||||||
clientDimension * distanceFromStart,
|
|
||||||
scrollDimension,
|
|
||||||
scrollStart,
|
|
||||||
);
|
|
||||||
const distanceFromEndPx =
|
|
||||||
_distanceFromEndPx ||
|
|
||||||
Math.min(
|
|
||||||
clientDimension * distanceFromEnd,
|
|
||||||
scrollDimension,
|
|
||||||
scrollDimension - scrollStart - clientDimension,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
|
||||||
scrollDistance >=
|
|
||||||
(previousScrollStart < scrollStart
|
|
||||||
? scrollThresholdEnd
|
|
||||||
: scrollThresholdStart)
|
|
||||||
) {
|
|
||||||
setScrollDirection(previousScrollStart < scrollStart ? 'end' : 'start');
|
|
||||||
previousScrollStart = scrollStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
setReachStart(scrollStart <= 0);
|
|
||||||
setReachEnd(scrollStart + clientDimension >= scrollDimension);
|
|
||||||
setNearReachStart(scrollStart <= distanceFromStartPx);
|
|
||||||
setNearReachEnd(
|
|
||||||
scrollStart + clientDimension >= scrollDimension - distanceFromEndPx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
scrollableElement.addEventListener('scroll', onScroll, { passive: true });
|
scrollableElement.addEventListener('scroll', onScroll, { passive: true });
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue