Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: useLockScroll whether the element scroll is in the end #6253 #6254

Merged
merged 9 commits into from
Aug 10, 2023
154 changes: 152 additions & 2 deletions src/utils/tests/use-lock-scroll.test.tsx
Original file line number Diff line number Diff line change
@@ -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<HTMLDivElement>(null)

useLockScroll(divRef, props.scrollParams)

return (
<div
ref={divRef}
data-testid='lock'
style={{
height: 200,
overflow: 'scroll',
cursor: 'grab',
touchAction: 'none',
}}
onTouchMove={() => props.handleTouch && props.handleTouch()}
>
{new Array(10).fill({}).map((_, i) => (
<h1 key={i} style={{ height: 25 }}>
Test component {i}
</h1>
))}
</div>
)
}
})

afterEach(() => {
TestComponent = null as any
})

test('use preventDefault when event listener is treated as as passive', () => {
const handleTouch = jest.fn()
const TestComponent = () => {
Expand Down Expand Up @@ -32,4 +72,114 @@ describe('useLockScroll', () => {

expect(fn).toBeCalled()
})

test('Scroll To Bottom', async () => {
const { getByTestId } = render(<TestComponent scrollParams={true} />)

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(<TestComponent scrollParams={true} />)

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(<TestComponent scrollParams='strict' />)

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()
})
})
3 changes: 2 additions & 1 deletion src/utils/use-lock-scroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
}

Expand Down
Loading