diff --git a/src/utils/tests/use-lock-scroll.test.tsx b/src/utils/tests/use-lock-scroll.test.tsx index d294743421..f37e487a16 100644 --- a/src/utils/tests/use-lock-scroll.test.tsx +++ b/src/utils/tests/use-lock-scroll.test.tsx @@ -1,8 +1,48 @@ -import React, { useRef, createRef } from 'react' -import { render, fireEvent, screen, createEvent } from 'testing' +import React, { useRef } from 'react' +import { render, fireEvent, createEvent, screen } from 'testing' import { useLockScroll } from '../use-lock-scroll' describe('useLockScroll', () => { + let TestComponent: React.FC<{ + scrollParams: boolean | 'strict' + handleTouch?: () => void + }> + + beforeEach(() => { + TestComponent = (props: { + scrollParams: boolean | 'strict' + handleTouch?: () => void + }) => { + const divRef = useRef(null) + + useLockScroll(divRef, props.scrollParams) + + return ( +
props.handleTouch && props.handleTouch()} + > + {new Array(10).fill({}).map((_, i) => ( +

+ Test component {i} +

+ ))} +
+ ) + } + }) + + afterEach(() => { + TestComponent = null as any + }) + test('use preventDefault when event listener is treated as as passive', () => { const handleTouch = jest.fn() const TestComponent = () => { @@ -32,4 +72,114 @@ describe('useLockScroll', () => { expect(fn).toBeCalled() }) + + test('Scroll To Bottom', async () => { + const { getByTestId } = render() + + const testEl = getByTestId('lock') + + jest.spyOn(testEl, 'scrollHeight', 'get').mockImplementation(() => 200) + + const scrollTop = jest.spyOn(testEl, 'scrollTop', 'get') + scrollTop.mockImplementationOnce(() => 150) + + jest.spyOn(testEl, 'getBoundingClientRect').mockImplementation(() => ({ + height: 20, + top: 0, + left: 0, + x: 0, + y: 0, + bottom: 0, + right: 0, + width: 0, + toJSON: () => {}, + })) + + fireEvent.touchStart(testEl, { + touches: [{ clientX: 0, clientY: 100 }], + }) + + const triggerTruthy = fireEvent.touchMove(testEl, { + touches: [{ clientX: 0, clientY: 20 }], + }) + // 滚动事件正常触发 + expect(triggerTruthy).toBeTruthy() + + // 滚动高度到 180 + scrollTop.mockImplementationOnce(() => 180) + + const triggerFalsy = fireEvent.touchMove(testEl, { + touches: [{ clientX: 0, clientY: 10 }], + }) + + // 滚动事件被取消 + expect(triggerFalsy).toBeFalsy() + }) + + test('Scroll To Top', async () => { + const { getByTestId } = render() + + const testEl = getByTestId('lock') + + jest.spyOn(testEl, 'scrollHeight', 'get').mockImplementation(() => 200) + + const scrollTop = jest.spyOn(testEl, 'scrollTop', 'get') + scrollTop.mockImplementationOnce(() => 150) + + jest.spyOn(testEl, 'getBoundingClientRect').mockImplementation(() => ({ + height: 20, + top: 0, + left: 0, + x: 0, + y: 0, + bottom: 0, + right: 0, + width: 0, + toJSON: () => {}, + })) + + fireEvent.touchStart(testEl, { + touches: [{ clientX: 0, clientY: 100 }], + }) + + const triggerTruthy = fireEvent.touchMove(testEl, { + touches: [{ clientX: 0, clientY: 120 }], + }) + // 滚动事件正常触发 + expect(triggerTruthy).toBeTruthy() + + // 滚动高度到顶部 + scrollTop.mockImplementationOnce(() => 0) + + const triggerFalsy = fireEvent.touchMove(testEl, { + touches: [{ clientX: 0, clientY: 200 }], + }) + + // 滚动事件被取消 + expect(triggerFalsy).toBeFalsy() + }) + + test('Scroll With Strict Params', async () => { + const { getByTestId } = render() + + const testEl = getByTestId('lock') + + jest + .spyOn(document.body, 'clientHeight', 'get') + .mockImplementation(() => 20) + jest + .spyOn(document.body, 'scrollHeight', 'get') + .mockImplementation(() => 30) + + fireEvent.touchStart(testEl, { + touches: [{ clientX: 0, clientY: 100 }], + }) + + const cancelTrigger = fireEvent.touchMove(testEl, { + touches: [{ clientX: 0, clientY: 200 }], + }) + + // 事件被取消 + expect(cancelTrigger).toBeFalsy() + }) }) diff --git a/src/utils/use-lock-scroll.ts b/src/utils/use-lock-scroll.ts index 97301d308d..755a138821 100644 --- a/src/utils/use-lock-scroll.ts +++ b/src/utils/use-lock-scroll.ts @@ -51,11 +51,12 @@ export function useLockScroll( } const { scrollHeight, offsetHeight, scrollTop } = el + const { height } = el.getBoundingClientRect() let status = '11' if (scrollTop === 0) { status = offsetHeight >= scrollHeight ? '00' : '01' - } else if (scrollTop + offsetHeight >= scrollHeight) { + } else if (scrollHeight <= Math.round(height + scrollTop)) { status = '10' }