Skip to content

Commit 6da8b08

Browse files
authored
feat(scroll-position): support pass ref object as scroll target (ecomfe#85)
1 parent cf3644f commit 6da8b08

File tree

3 files changed

+38
-11
lines changed

3 files changed

+38
-11
lines changed

packages/scroll-position/docs/demo/useScrollPosition.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {useScrollPosition} from '@huse/scroll-position';
33

44
export default () => {
55
const ref = useRef(null);
6-
const position = useScrollPosition(ref.current);
6+
const position = useScrollPosition(ref);
77
const gradient = 'radial-gradient(circle at 10% 20%, rgb(6, 123, 239) 14.2%, rgb(219, 115, 249) 89.5%)';
88
console.log('position---->', position);
99
return (

packages/scroll-position/src/__tests__/index.test.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import {useEffect, useRef} from 'react';
12
import {renderHook} from '@testing-library/react-hooks';
3+
import {render} from '@testing-library/react';
24
import {useScrollPosition, useScrollLeft, useScrollTop} from '../index';
35

46
describe('useScrollPosition', () => {
@@ -7,6 +9,21 @@ describe('useScrollPosition', () => {
79
expect(result.current).toEqual({x: 0, y: 0, left: 0, top: 0, scrollLeft: 0, scrollTop: 0});
810
});
911

12+
test('pass ref', () => {
13+
let scroll = null;
14+
let ref = null;
15+
const Foo = () => {
16+
ref = useRef(null);
17+
useEffect(() => {
18+
ref.current.scrollTop = 10;
19+
}, []);
20+
scroll = useScrollPosition(ref);
21+
return <span ref={ref} id="root" />;
22+
};
23+
render(<Foo />);
24+
expect(scroll).toEqual({x: 0, y: 10, left: 0, top: 10, scrollLeft: 0, scrollTop: 10});
25+
});
26+
1027
test('element scroll position', () => {
1128
const div = document.createElement('div');
1229
div.scrollTop = 10;

packages/scroll-position/src/index.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {useRef, useEffect, useState} from 'react';
1+
import {useRef, useEffect, useState, MutableRefObject} from 'react';
22
import hasPassiveEvent from 'has-passive-events';
33

44
export interface ScrollPosition {
@@ -28,18 +28,28 @@ const getScrollPosition = (element: HTMLElement): ScrollPosition => {
2828
};
2929
};
3030

31-
export function useScrollPosition(element?: HTMLElement | null): ScrollPosition {
31+
type Target = MutableRefObject<HTMLElement> | HTMLElement | null;
32+
33+
function getTargetNode(target?: Target): HTMLElement | Document {
34+
if (!target) {
35+
return document;
36+
}
37+
if ('current' in target) {
38+
return target.current;
39+
}
40+
return target;
41+
}
42+
43+
export function useScrollPosition(target?: Target): ScrollPosition {
3244
const rafTick = useRef(0);
3345
const [position, setPosition] = useState(INITIAL_POSITION);
3446
useEffect(
3547
() => {
36-
if (element === null) {
48+
if (target === null) {
3749
return;
3850
}
39-
40-
const target = element ?? document;
41-
const targetElement = element ?? document.documentElement;
42-
51+
const targetNode = getTargetNode(target);
52+
const targetElement = targetNode === document ? document.documentElement : targetNode as HTMLElement;
4353
setPosition(getScrollPosition(targetElement));
4454

4555
const syncScroll = () => {
@@ -54,14 +64,14 @@ export function useScrollPosition(element?: HTMLElement | null): ScrollPosition
5464
rafTick.current = requestAnimationFrame(callback);
5565
};
5666

57-
target.addEventListener('scroll', syncScroll, EVENT_OPTIONS);
67+
targetNode.addEventListener('scroll', syncScroll, EVENT_OPTIONS);
5868

5969
return () => {
60-
target.removeEventListener('scroll', syncScroll, EVENT_OPTIONS);
70+
targetNode.removeEventListener('scroll', syncScroll, EVENT_OPTIONS);
6171
cancelAnimationFrame(rafTick.current);
6272
};
6373
},
64-
[element]
74+
[target]
6575
);
6676

6777
return position;

0 commit comments

Comments
 (0)