useScroll
useScroll(target?: Element | Window): Service<ScrollProps>Scroll position, movement and direction for one scroller. With no target it is the document element; useScroll(document.documentElement) is the window service.
Props
interface ScrollProps {
readonly x: number;
readonly y: number;
readonly deltaX: number;
readonly deltaY: number;
readonly maxX: number;
readonly maxY: number;
readonly progressX: number;
readonly progressY: number;
readonly directionX: -1 | 0 | 1;
readonly directionY: -1 | 0 | 1;
readonly isScrolling: boolean;
}Nothing derivable is a field: lastX is x - deltaX, and changedX is deltaX !== 0.
Usage
import { Base, useScroll } from '@studiometa/js-toolkit';
class Header extends Base {
static config = { name: 'Header' };
mounted() {
return useScroll().subscribe(({ y, directionY }) => {
this.$el.classList.toggle('is-hidden', directionY > 0 && y > 100);
});
}
}A region rather than the page:
import { Base, useScroll } from '@studiometa/js-toolkit';
class Panel extends Base {
static config = { name: 'Panel', refs: ['scroller'] };
mounted() {
return useScroll(this.$refs.scroller).subscribe(({ progressY }) => {
this.$el.style.setProperty('--progress', String(progressY));
});
}
}One read per frame
The service coalesces its scroll events into one read per frame, so a page scrolling at speed measures once per frame rather than once per event.
Extents are observed, not sampled once
The service watches the scroller and its element children with a ResizeObserver, plus a childList MutationObserver to keep that set correct: 1 + n observed boxes per scroller, lazy and released with the last subscriber.
That is what keeps maxY and progressY correct when content is added, removed or resized.
{ immediate: true } works here
A scroller has a current position between deliveries, so the first delivery is honoured. The first props of a run carry no movement: the deltas are zero and directionX/directionY are 0.
Mixin
class Header extends withScroll(Base) {
scrolled({ y, directionY }) {}
}withScroll defaults to the page-wide source. A region is withScroll(Base, { target: (instance) => instance.$refs.scroller }).
See also
useWindowScroll()— the named default caseuseScrollProgress()— an element's progress through the viewport