diff --git a/config/hooks.ts b/config/hooks.ts index 26ffff428a..04f70b18ef 100644 --- a/config/hooks.ts +++ b/config/hooks.ts @@ -101,6 +101,7 @@ export const menus = [ 'useScroll', 'useSize', 'useFocusWithin', + 'useStickyFixed', ], }, { diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts index 55c7232b0d..c84d76f81b 100644 --- a/packages/hooks/src/index.ts +++ b/packages/hooks/src/index.ts @@ -76,6 +76,7 @@ import useWebSocket from './useWebSocket'; import useWhyDidYouUpdate from './useWhyDidYouUpdate'; import useMutationObserver from './useMutationObserver'; import useTheme from './useTheme'; +import useStickyFixed from './useStickyFixed'; export { useRequest, @@ -158,4 +159,5 @@ export { useResetState, useMutationObserver, useTheme, + useStickyFixed, }; diff --git a/packages/hooks/src/useStickyFixed/__tests__/index.test.ts b/packages/hooks/src/useStickyFixed/__tests__/index.test.ts new file mode 100644 index 0000000000..7f6bd2ccd1 --- /dev/null +++ b/packages/hooks/src/useStickyFixed/__tests__/index.test.ts @@ -0,0 +1,42 @@ +import { act, renderHook } from '@testing-library/react'; +import useStickyFixed from '../index'; + +const scrollElement = document.createElement('div'); +scrollElement.style.overflowY = 'scroll'; +scrollElement.style.height = '200px'; // 设置高度以允许滚动 +scrollElement.style.width = '200px'; // 设置高度以允许滚动 +document.body.appendChild(scrollElement); + +const topElement = document.createElement('div'); //top元素用于填充 +topElement.style.height = '100px'; +scrollElement.appendChild(topElement); + +const targetElement = document.createElement('div'); // 模拟 sticky 的元素 +targetElement.style.position = 'sticky'; +targetElement.style.top = '0'; +targetElement.style.height = '20px'; //其他元素用于填充 +scrollElement.appendChild(targetElement); + +const bottomElement = document.createElement('div'); //bottom元素用于填充 +bottomElement.style.height = '200px'; +scrollElement.appendChild(bottomElement); + +describe('useStickyFixed', () => { + it('should set state to false when not scrolling', () => { + const { result } = renderHook(() => useStickyFixed(targetElement, { scrollTarget: scrollElement })); + + // 开始未滚动 返回false + expect(result.current[0]).toBe(false); + }); + + it('should not throw if target is not found', () => { + const { result } = renderHook(() => useStickyFixed(null, { scrollTarget: scrollElement })); + + act(() => { + scrollElement.scrollTop = 0; + scrollElement.dispatchEvent(new Event('scroll')); + }); + + expect(result.current[0]).toBe(false); // 没有抛出错误 + }); +}); diff --git a/packages/hooks/src/useStickyFixed/demo/demo1.tsx b/packages/hooks/src/useStickyFixed/demo/demo1.tsx new file mode 100644 index 0000000000..048f193c38 --- /dev/null +++ b/packages/hooks/src/useStickyFixed/demo/demo1.tsx @@ -0,0 +1,47 @@ +/** + * title: Basic usage + * desc: Need to input the sticky positioning element target and the rolling container scrollTarget, ScrollTarget defaults to document + * + * title.zh-CN: 基础用法 + * desc.zh-CN: 需要传入粘性定位元素target和滚动容器scrollTarget, scrollTarget默认为document + * + */ + +import React, { useRef, useState } from 'react'; +import { useStickyFixed } from 'ahooks'; + +export default () => { + const [topV, setTopV] = useState(0); + + const targetRef = useRef(null); + const scrollTargetRef = useRef(null); + + const [isFixed] = useStickyFixed(targetRef, { scrollTarget: scrollTargetRef }); + + const fixedStyle = { background: 'pink' }; + + return ( + <> +
+
+### Pass in DOM element
+
+
+
+## API
+
+```typescript
+const [isFixed] = useStickyFixed(targetRef, { scrollTarget });
+```
+
+### Params
+
+| Property | Description | Type | Default |
+| -------- | ---------------------------------------- | ----------------------------------------------------------- | ------- |
+| target | `position: sticky` 's Dom element or ref | `() => Element` \| `Element` \| `MutableRefObject
+
+### 传入 DOM 元素
+
+
+
+## API
+
+```typescript
+const [isFixed] = useStickyFixed(targetRef, { scrollTarget });
+```
+
+### Params
+
+| 参数 | 说明 | 类型 | 默认值 |
+| ------- | -------------------------------- | ---------------------------------------------------------- | ------ |
+| target | 粘性定位的 DOM 节点或者 Ref 对象 | `Element` \|`() => Element` \| `MutableRefObject