From 5db14cf0330d65576ef8412289d2b01c6c470ec2 Mon Sep 17 00:00:00 2001 From: FatttSnake Date: Sun, 24 Sep 2023 13:01:58 +0800 Subject: [PATCH] Refactor the HideScrollbar. Finish scrollbar in HideScrollbar. --- .../css/components/common/hide-scrollbar.scss | 6 +- src/components/common/HideScrollbar.tsx | 402 +++++++++++------- src/components/home/index.tsx | 2 +- src/pages/MainFramework.tsx | 7 +- 4 files changed, 257 insertions(+), 160 deletions(-) diff --git a/src/assets/css/components/common/hide-scrollbar.scss b/src/assets/css/components/common/hide-scrollbar.scss index 544de0b..3aaa0b8 100644 --- a/src/assets/css/components/common/hide-scrollbar.scss +++ b/src/assets/css/components/common/hide-scrollbar.scss @@ -10,6 +10,10 @@ overflow: scroll; scrollbar-width: none; -ms-overflow-style: none; + + .hide-scrollbar-content { + display: inline-block; + } } ::-webkit-scrollbar { @@ -35,7 +39,7 @@ height: 100%; border-radius: 8px; background-color: constants.$font-secondary-color; - transition: all .2s; + transition: background-color .2s; } :hover { background-color: constants.$font-main-color; diff --git a/src/components/common/HideScrollbar.tsx b/src/components/common/HideScrollbar.tsx index 9afbc9d..9799a81 100644 --- a/src/components/common/HideScrollbar.tsx +++ b/src/components/common/HideScrollbar.tsx @@ -43,126 +43,6 @@ export interface HideScrollbarElement { } const HideScrollbar = forwardRef((props, ref) => { - const rootRef = useRef(null) - const lastTouchPosition = useRef<{ x: number; y: number }>({ x: -1, y: -1 }) - const [verticalScrollbarWidth, setVerticalScrollbarWidth] = useState(0) - const [horizontalScrollbarWidth, setHorizontalScrollbarWidth] = useState(0) - const [verticalScrollbarLength, setVerticalScrollbarLength] = useState(100) - const [horizontalScrollbarLength, setHorizontalScrollbarLength] = useState(100) - - const { - isPreventScroll, - isPreventVerticalScroll, - isPreventHorizontalScroll, - isShowVerticalScrollbar, - isShowHorizontalScrollbar, - ..._props - } = props - - const handleDefaultWheel = useCallback( - (event: WheelEvent) => { - if (!event.altKey && !event.ctrlKey) { - if (isPreventScroll) { - 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) => { - if (event.button === 1) { - event.preventDefault() - } - }, []) - - const handleDefaultKeyDown = useCallback( - (event: KeyboardEvent) => { - if ( - isPreventScroll && - [ - 'ArrowUp', - 'ArrowDown', - 'ArrowLeft', - 'ArrowRight', - ' ', - '', - 'PageUp', - 'PageDown', - 'Home', - 'End' - ].find((value) => value === event.key) - ) { - 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( ref, () => { @@ -249,78 +129,276 @@ const HideScrollbar = forwardRef((prop [] ) - useEffect(() => { - const hideScrollbarElement = rootRef.current + const maskRef = useRef(null) + const rootRef = useRef(null) + const contentRef = useRef(null) + const wheelListenerRef = useRef<(event: WheelEvent) => void>(() => undefined) + const lastClickPositionRef = useRef({ x: -1, y: -1 }) + const lastTouchPositionRef = useRef({ x: -1, y: -1 }) + const [verticalScrollbarWidth, setVerticalScrollbarWidth] = useState(0) + const [verticalScrollbarLength, setVerticalScrollbarLength] = useState(100) + const [verticalScrollbarPosition, setVerticalScrollbarPosition] = useState(0) + const [verticalScrollbarOnClick, setVerticalScrollbarOnClick] = useState(false) + const [horizontalScrollbarWidth, setHorizontalScrollbarWidth] = useState(0) + const [horizontalScrollbarLength, setHorizontalScrollbarLength] = useState(100) + const [horizontalScrollbarPosition, setHorizontalScrollbarPosition] = useState(0) + const [horizontalScrollbarOnClick, setHorizontalScrollbarOnClick] = useState(false) + const { + isPreventScroll, + isPreventVerticalScroll, + isPreventHorizontalScroll, + isShowVerticalScrollbar, + isShowHorizontalScrollbar, + ..._props + } = props + + const isPreventAnyScroll = + isPreventScroll || isPreventVerticalScroll || isPreventHorizontalScroll + + const handleDefaultTouchStart = useCallback( + (event: React.TouchEvent) => { + if (event.touches.length !== 1 || isPreventScroll) { + lastTouchPositionRef.current = { x: -1, y: -1 } + return + } + + const { clientX, clientY } = event.touches[0] + lastTouchPositionRef.current = { x: clientX, y: clientY } + }, + [isPreventScroll] + ) + + const handleDefaultTouchmove = useCallback( + (event: React.TouchEvent) => { + if (event.touches.length !== 1 || isPreventScroll) { + lastTouchPositionRef.current = { x: -1, y: -1 } + return + } + const { clientX, clientY } = event.touches[0] + + if (!isPreventVerticalScroll) { + rootRef.current?.scrollTo({ + top: rootRef.current?.scrollTop + (lastTouchPositionRef.current.y - clientY), + behavior: 'instant' + }) + } + + if (!isPreventHorizontalScroll) { + rootRef.current?.scrollTo({ + left: rootRef.current?.scrollLeft + (lastTouchPositionRef.current.x - clientX), + behavior: 'instant' + }) + } + + lastTouchPositionRef.current = { x: clientX, y: clientY } + }, + [isPreventHorizontalScroll, isPreventScroll, isPreventVerticalScroll] + ) + + const handleDefaultMouseDown = (event: React.MouseEvent) => { + if (isPreventAnyScroll) + if (event.button === 1) { + event.preventDefault() + } + } + + const handleDefaultKeyDown = useCallback( + (event: React.KeyboardEvent) => { + if ( + isPreventScroll && + [ + 'ArrowUp', + 'ArrowDown', + 'ArrowLeft', + 'ArrowRight', + ' ', + '', + 'PageUp', + 'PageDown', + 'Home', + 'End' + ].find((value) => value === event.key) + ) { + 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() + } + }, + [isPreventHorizontalScroll, isPreventScroll, isPreventVerticalScroll] + ) + + const handleScrollbarMouseEvent = (eventFlag: string, scrollbarFlag: string) => { + return (event: React.MouseEvent) => { + switch (eventFlag) { + case 'down': + lastClickPositionRef.current = { x: event.clientX, y: event.clientY } + switch (scrollbarFlag) { + case 'vertical': + setVerticalScrollbarOnClick(true) + break + case 'horizontal': + setHorizontalScrollbarOnClick(true) + break + } + break + case 'up': + case 'leave': + setVerticalScrollbarOnClick(false) + setHorizontalScrollbarOnClick(false) + break + case 'move': + if (verticalScrollbarOnClick) { + rootRef.current?.scrollTo({ + top: + rootRef.current?.scrollTop + + ((event.clientY - lastClickPositionRef.current.y) / + (rootRef.current?.clientHeight ?? 1)) * + (contentRef.current?.clientHeight ?? 0), + behavior: 'instant' + }) + } + if (horizontalScrollbarOnClick) { + rootRef.current?.scrollTo({ + left: + rootRef.current?.scrollLeft + + ((event.clientX - lastClickPositionRef.current.x) / + (rootRef.current?.clientWidth ?? 1)) * + (contentRef.current?.clientWidth ?? 0), + behavior: 'instant' + }) + } + lastClickPositionRef.current = { + x: event.clientX, + y: event.clientY + } + } + } + } + + const handleDefaultScroll = () => { + setVerticalScrollbarPosition( + ((rootRef.current?.scrollTop ?? 0) / (contentRef.current?.clientHeight ?? 1)) * 100 + ) + setHorizontalScrollbarPosition( + ((rootRef.current?.scrollLeft ?? 0) / (contentRef.current?.clientWidth ?? 1)) * 100 + ) + } + + useEffect(() => { const windowResizeListener = () => { setVerticalScrollbarWidth( - (hideScrollbarElement?.offsetWidth ?? 0) - (hideScrollbarElement?.clientWidth ?? 0) + (rootRef.current?.offsetWidth ?? 0) - (rootRef.current?.clientWidth ?? 0) ) setHorizontalScrollbarWidth( - (hideScrollbarElement?.offsetHeight ?? 0) - - (hideScrollbarElement?.clientHeight ?? 0) + (rootRef.current?.offsetHeight ?? 0) - (rootRef.current?.clientHeight ?? 0) ) return windowResizeListener } - setTimeout(() => { windowResizeListener() }, 1000) - window.addEventListener('resize', windowResizeListener()) - if (isPreventScroll || isPreventVerticalScroll || isPreventHorizontalScroll) { + + rootRef.current?.removeEventListener('wheel', wheelListenerRef.current) + if (isPreventAnyScroll) { + const handleDefaultWheel = (event: WheelEvent) => { + if (!event.altKey && !event.ctrlKey) { + if (isPreventScroll) { + event.preventDefault() + return + } + if (isPreventVerticalScroll && !event.shiftKey && !event.deltaX) { + event.preventDefault() + return + } + if (isPreventHorizontalScroll && (event.shiftKey || !event.deltaY)) { + event.preventDefault() + return + } + } + } + wheelListenerRef.current = handleDefaultWheel rootRef.current?.addEventListener('wheel', handleDefaultWheel, { passive: false }) - rootRef.current?.addEventListener('touchstart', handleDefaultTouchStart, { - passive: false - }) - rootRef.current?.addEventListener('touchmove', handleDefaultTouchmove, { - passive: false - }) - rootRef.current?.addEventListener('mousedown', handleDefaultClickMiddleMouseButton) - rootRef.current?.addEventListener('keydown', handleDefaultKeyDown) - } else { - rootRef.current?.removeEventListener('wheel', handleDefaultWheel) - rootRef.current?.removeEventListener('touchstart', handleDefaultTouchStart) - rootRef.current?.removeEventListener('touchmove', handleDefaultTouchmove) - rootRef.current?.removeEventListener('mousedown', handleDefaultClickMiddleMouseButton) - rootRef.current?.removeEventListener('keydown', handleDefaultKeyDown) } + rootRef.current && + setVerticalScrollbarLength( + (rootRef.current.clientHeight / (contentRef.current?.clientHeight ?? 0)) * 100 + ) + + rootRef.current && + setHorizontalScrollbarLength( + (rootRef.current.clientWidth / (contentRef.current?.clientWidth ?? 0)) * 100 + ) + return () => { window.removeEventListener('resize', windowResizeListener) } - }, [ - handleDefaultClickMiddleMouseButton, - handleDefaultKeyDown, - handleDefaultTouchStart, - handleDefaultTouchmove, - handleDefaultWheel, - isPreventHorizontalScroll, - isPreventScroll, - isPreventVerticalScroll - ]) + }, [isPreventAnyScroll, isPreventHorizontalScroll, isPreventScroll, isPreventVerticalScroll]) return ( <> -
+
- {props.children} +
+ {props.children} +