Add logo.png to public. Add vertical and horizontal scroll prevent. Fix scroll index out-of-bounds bug. #21

Merged
FatttSnake merged 5 commits from FatttSnake into dev 2023-09-22 16:33:13 +08:00
2 changed files with 141 additions and 51 deletions
Showing only changes of commit 37f35aa0d0 - Show all commits

View File

@@ -4,16 +4,20 @@ import '@/assets/css/components/common/hide-scrollbar.scss'
interface HideScrollbarProps interface HideScrollbarProps
extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> { extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
isPreventScroll?: boolean isPreventScroll?: boolean
isPreventVerticalScroll?: boolean
isPreventHorizontalScroll?: boolean
isShowVerticalScrollbar?: boolean
isShowHorizontalScrollbar?: boolean
} }
export interface HideScrollbarElement { export interface HideScrollbarElement {
scrollTo(x: number, y: number): void scrollTo(x: number, y: number, smooth?: boolean): void
scrollX(x: number): void scrollX(x: number, smooth?: boolean): void
scrollY(y: number): void scrollY(y: number, smooth?: boolean): void
scrollLeft(length: number): void scrollLeft(length: number, smooth?: boolean): void
scrollRight(length: number): void scrollRight(length: number, smooth?: boolean): void
scrollUp(length: number): void scrollUp(length: number, smooth?: boolean): void
scrollDown(length: number): void scrollDown(length: number, smooth?: boolean): void
getX(): number getX(): number
getY(): number getY(): number
addEventListenerWithType<K extends keyof HTMLElementEventMap>( addEventListenerWithType<K extends keyof HTMLElementEventMap>(
@@ -40,19 +44,79 @@ export interface HideScrollbarElement {
const HideScrollbar = forwardRef<HideScrollbarElement, HideScrollbarProps>((props, ref) => { const HideScrollbar = forwardRef<HideScrollbarElement, HideScrollbarProps>((props, ref) => {
const rootRef = useRef<HTMLDivElement>(null) const rootRef = useRef<HTMLDivElement>(null)
const lastTouchPosition = useRef<{ x: number; y: number }>({ x: -1, y: -1 })
const [verticalScrollbarWidth, setVerticalScrollbarWidth] = useState(0) const [verticalScrollbarWidth, setVerticalScrollbarWidth] = useState(0)
const [horizontalScrollbarWidth, setHorizontalScrollbarWidth] = useState(0) const [horizontalScrollbarWidth, setHorizontalScrollbarWidth] = useState(0)
const { isPreventScroll, ..._props } = props const {
const handleDefaultWheel = useCallback((event: WheelEvent) => { isPreventScroll,
if (!event.altKey && !event.ctrlKey) { isPreventVerticalScroll,
event.preventDefault() isPreventHorizontalScroll,
} isShowVerticalScrollbar,
}, []) isShowHorizontalScrollbar,
..._props
} = props
const handleDefaultTouchmove = useCallback((event: TouchEvent) => { const handleDefaultWheel = useCallback(
(event: WheelEvent) => {
if (!event.altKey && !event.ctrlKey) {
if (isPreventScroll) {
event.preventDefault() event.preventDefault()
}, []) return
}
if (isPreventVerticalScroll && !event.shiftKey && !event.deltaX) {
event.preventDefault()
return
}
if (isPreventHorizontalScroll && (event.shiftKey || !event.deltaY)) {
event.preventDefault()
return
}
}
},
[isPreventScroll, isPreventHorizontalScroll, isPreventVerticalScroll]
)
const handleDefaultTouchStart = useCallback(
(event: TouchEvent) => {
if (event.touches.length !== 1 || isPreventScroll) {
lastTouchPosition.current = { x: -1, y: -1 }
return
}
const { clientX, clientY } = event.touches[0]
lastTouchPosition.current = { x: clientX, y: clientY }
},
[isPreventScroll]
)
const handleDefaultTouchmove = useCallback(
(event: TouchEvent) => {
event.preventDefault()
if (event.touches.length !== 1 || isPreventScroll) {
lastTouchPosition.current = { x: -1, y: -1 }
return
}
const { clientX, clientY } = event.touches[0]
if (!isPreventVerticalScroll) {
rootRef.current?.scrollTo({
top: rootRef.current?.scrollTop + (lastTouchPosition.current.y - clientY),
behavior: 'instant'
})
}
if (!isPreventHorizontalScroll) {
rootRef.current?.scrollTo({
left: rootRef.current?.scrollLeft + (lastTouchPosition.current.x - clientX),
behavior: 'instant'
})
}
lastTouchPosition.current = { x: clientX, y: clientY }
},
[isPreventScroll, isPreventHorizontalScroll, isPreventVerticalScroll]
)
const handleDefaultClickMiddleMouseButton = useCallback((event: MouseEvent) => { const handleDefaultClickMiddleMouseButton = useCallback((event: MouseEvent) => {
if (event.button === 1) { if (event.button === 1) {
@@ -60,8 +124,10 @@ const HideScrollbar = forwardRef<HideScrollbarElement, HideScrollbarProps>((prop
} }
}, []) }, [])
const handleDefaultKeyDown = (event: KeyboardEvent) => { const handleDefaultKeyDown = useCallback(
(event: KeyboardEvent) => {
if ( if (
isPreventScroll &&
[ [
'ArrowUp', 'ArrowUp',
'ArrowDown', 'ArrowDown',
@@ -77,53 +143,69 @@ const HideScrollbar = forwardRef<HideScrollbarElement, HideScrollbarProps>((prop
) { ) {
event.preventDefault() event.preventDefault()
} }
if (
isPreventVerticalScroll &&
['ArrowUp', 'ArrowDown', ' ', '', 'PageUp', 'PageDown', 'Home', 'End'].find(
(value) => value === event.key
)
) {
event.preventDefault()
} }
if (
isPreventHorizontalScroll &&
['ArrowLeft', 'ArrowRight'].find((value) => value === event.key)
) {
event.preventDefault()
}
},
[isPreventScroll, isPreventHorizontalScroll, isPreventVerticalScroll]
)
useImperativeHandle<HideScrollbarElement, HideScrollbarElement>( useImperativeHandle<HideScrollbarElement, HideScrollbarElement>(
ref, ref,
() => { () => {
return { return {
scrollTo(x, y) { scrollTo(x, y, smooth?: boolean) {
rootRef.current?.scrollTo({ rootRef.current?.scrollTo({
left: x, left: x,
top: y, top: y,
behavior: 'smooth' behavior: smooth === false ? 'instant' : 'smooth'
}) })
}, },
scrollX(x) { scrollX(x, smooth?: boolean) {
rootRef.current?.scrollTo({ rootRef.current?.scrollTo({
left: x, left: x,
behavior: 'smooth' behavior: smooth === false ? 'instant' : 'smooth'
}) })
}, },
scrollY(y) { scrollY(y, smooth?: boolean) {
rootRef.current?.scrollTo({ rootRef.current?.scrollTo({
top: y, top: y,
behavior: 'smooth' behavior: smooth === false ? 'instant' : 'smooth'
}) })
}, },
scrollLeft(length) { scrollLeft(length, smooth?: boolean) {
rootRef.current?.scrollTo({ rootRef.current?.scrollTo({
left: rootRef.current?.scrollLeft - length, left: rootRef.current?.scrollLeft - length,
behavior: 'smooth' behavior: smooth === false ? 'instant' : 'smooth'
}) })
}, },
scrollRight(length) { scrollRight(length, smooth?: boolean) {
rootRef.current?.scrollTo({ rootRef.current?.scrollTo({
left: rootRef.current?.scrollLeft + length, left: rootRef.current?.scrollLeft + length,
behavior: 'smooth' behavior: smooth === false ? 'instant' : 'smooth'
}) })
}, },
scrollUp(length) { scrollUp(length, smooth?: boolean) {
rootRef.current?.scrollTo({ rootRef.current?.scrollTo({
top: rootRef.current?.scrollTop - length, top: rootRef.current?.scrollTop - length,
behavior: 'smooth' behavior: smooth === false ? 'instant' : 'smooth'
}) })
}, },
scrollDown(length) { scrollDown(length, smooth?: boolean) {
rootRef.current?.scrollTo({ rootRef.current?.scrollTo({
top: rootRef.current?.scrollTop + length, top: rootRef.current?.scrollTop + length,
behavior: 'smooth' behavior: smooth === false ? 'instant' : 'smooth'
}) })
}, },
getX() { getX() {
@@ -185,8 +267,11 @@ const HideScrollbar = forwardRef<HideScrollbarElement, HideScrollbarProps>((prop
}, 1000) }, 1000)
window.addEventListener('resize', windowResizeListener()) window.addEventListener('resize', windowResizeListener())
if (isPreventScroll) { if (isPreventScroll || isPreventVerticalScroll || isPreventHorizontalScroll) {
rootRef.current?.addEventListener('wheel', handleDefaultWheel, { passive: false }) rootRef.current?.addEventListener('wheel', handleDefaultWheel, { passive: false })
rootRef.current?.addEventListener('touchstart', handleDefaultTouchStart, {
passive: false
})
rootRef.current?.addEventListener('touchmove', handleDefaultTouchmove, { rootRef.current?.addEventListener('touchmove', handleDefaultTouchmove, {
passive: false passive: false
}) })
@@ -194,6 +279,7 @@ const HideScrollbar = forwardRef<HideScrollbarElement, HideScrollbarProps>((prop
rootRef.current?.addEventListener('keydown', handleDefaultKeyDown) rootRef.current?.addEventListener('keydown', handleDefaultKeyDown)
} else { } else {
rootRef.current?.removeEventListener('wheel', handleDefaultWheel) rootRef.current?.removeEventListener('wheel', handleDefaultWheel)
rootRef.current?.removeEventListener('touchstart', handleDefaultTouchStart)
rootRef.current?.removeEventListener('touchmove', handleDefaultTouchmove) rootRef.current?.removeEventListener('touchmove', handleDefaultTouchmove)
rootRef.current?.removeEventListener('mousedown', handleDefaultClickMiddleMouseButton) rootRef.current?.removeEventListener('mousedown', handleDefaultClickMiddleMouseButton)
rootRef.current?.removeEventListener('keydown', handleDefaultKeyDown) rootRef.current?.removeEventListener('keydown', handleDefaultKeyDown)
@@ -204,9 +290,13 @@ const HideScrollbar = forwardRef<HideScrollbarElement, HideScrollbarProps>((prop
} }
}, [ }, [
handleDefaultClickMiddleMouseButton, handleDefaultClickMiddleMouseButton,
handleDefaultKeyDown,
handleDefaultTouchStart,
handleDefaultTouchmove, handleDefaultTouchmove,
handleDefaultWheel, handleDefaultWheel,
isPreventScroll isPreventHorizontalScroll,
isPreventScroll,
isPreventVerticalScroll
]) ])
return ( return (

View File

@@ -43,7 +43,7 @@ const MainFramework: React.FC = () => {
return ( return (
<> <>
<HideScrollbar ref={hideScrollbarRef} isPreventScroll={preventScroll}> <HideScrollbar ref={hideScrollbarRef} isPreventVerticalScroll={preventScroll}>
<div className={'body'}> <div className={'body'}>
<header className={'nav' + (navbarHidden ? ' hide' : '')}> <header className={'nav' + (navbarHidden ? ' hide' : '')}>
<a className={'logo'} href={'https://fatweb.top'}> <a className={'logo'} href={'https://fatweb.top'}>