From 7d7450ddd98335f6d672670f4192baecaa62d1c2 Mon Sep 17 00:00:00 2001 From: FatttSnake Date: Mon, 11 Sep 2023 17:49:08 +0800 Subject: [PATCH 1/5] Add prevent scroll control to HideScrollbar --- src/components/FitCenter.tsx | 2 +- src/components/FitFullScreen.tsx | 3 +- src/components/HideScrollbar.tsx | 60 ++++++++++++++++++++++++++++++-- src/pages/MainFramework.tsx | 37 ++++++++++++++++---- vite.config.ts | 5 --- 5 files changed, 92 insertions(+), 15 deletions(-) diff --git a/src/components/FitCenter.tsx b/src/components/FitCenter.tsx index ede8b2e..ea15292 100644 --- a/src/components/FitCenter.tsx +++ b/src/components/FitCenter.tsx @@ -1,7 +1,7 @@ import React from 'react' import '@/assets/css/fit-center.scss' -const FitCenter: React.FC = (props: PropsWithChildren) => { +const FitCenter: React.FC = (props) => { return ( <>
{props.children}
diff --git a/src/components/FitFullScreen.tsx b/src/components/FitFullScreen.tsx index e356c2c..2dbebbe 100644 --- a/src/components/FitFullScreen.tsx +++ b/src/components/FitFullScreen.tsx @@ -1,6 +1,7 @@ +import React from 'react' import '@/assets/css/fit-fullscreen.scss' -interface FitFullscreenProps extends PropsWithChildren { +interface FitFullscreenProps extends React.PropsWithChildren { zIndex?: number backgroundColor?: string } diff --git a/src/components/HideScrollbar.tsx b/src/components/HideScrollbar.tsx index 52a4644..815f7fd 100644 --- a/src/components/HideScrollbar.tsx +++ b/src/components/HideScrollbar.tsx @@ -1,5 +1,11 @@ +import React from 'react' import '@/assets/css/hide-scrollbar.scss' +interface HideScrollbarProps + extends React.DetailedHTMLProps, HTMLDivElement> { + isPreventScroll?: boolean +} + export interface HideScrollbarElement { scrollTo(x: number, y: number): void scrollX(x: number): void @@ -32,11 +38,46 @@ export interface HideScrollbarElement { ): void } -const HideScrollbar = forwardRef((props, ref) => { +const HideScrollbar = forwardRef((props, ref) => { const rootRef = useRef(null) const [verticalScrollbarWidth, setVerticalScrollbarWidth] = useState(0) const [horizontalScrollbarWidth, setHorizontalScrollbarWidth] = useState(0) + const { isPreventScroll, ..._props } = props + + const handleDefaultWheel = (event: WheelEvent) => { + event.preventDefault() + } + + const handleDefaultTouchmove = (event: TouchEvent) => { + event.preventDefault() + } + + const handleDefaultClickMiddleMouseButton = (event: MouseEvent) => { + if (event.button === 1) { + event.preventDefault() + } + } + + const handleDefaultKeyDown = (event: KeyboardEvent) => { + if ( + [ + 'ArrowUp', + 'ArrowDown', + 'ArrowLeft', + 'ArrowRight', + ' ', + '', + 'PageUp', + 'PageDown', + 'Home', + 'End' + ].find((value) => value === event.key) + ) { + event.preventDefault() + } + } + useImperativeHandle( ref, () => { @@ -143,11 +184,24 @@ const HideScrollbar = forwardRef((props }, 1000) window.addEventListener('resize', windowResizeListener()) + if (isPreventScroll) { + rootRef.current?.addEventListener('wheel', handleDefaultWheel, { 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('touchmove', handleDefaultTouchmove) + rootRef.current?.removeEventListener('mousedown', handleDefaultClickMiddleMouseButton) + rootRef.current?.removeEventListener('keydown', handleDefaultKeyDown) + } return () => { window.removeEventListener('resize', windowResizeListener) } - }, []) + }, [isPreventScroll]) return ( <> @@ -155,10 +209,12 @@ const HideScrollbar = forwardRef((props
{props.children}
diff --git a/src/pages/MainFramework.tsx b/src/pages/MainFramework.tsx index 23ff379..d885588 100644 --- a/src/pages/MainFramework.tsx +++ b/src/pages/MainFramework.tsx @@ -9,30 +9,54 @@ export const MainFrameworkContext = createContext<{ navbarHidden: boolean setNavbarHidden: (newValue: boolean) => void } - hideScrollbarRef: RefObject + preventScrollState: { + preventScroll: boolean + setPreventScroll: (newValue: boolean) => void + } + hideScrollbarRef: React.RefObject }>({ navbarHiddenState: { navbarHidden: false, setNavbarHidden: () => undefined }, - hideScrollbarRef: createRef() + hideScrollbarRef: createRef(), + preventScrollState: { + preventScroll: false, + setPreventScroll: () => undefined + } }) const MainFramework: React.FC = () => { - const [navbarHidden, setNavbarHidden] = useState(true) - - const hideScrollbarRef = useRef(null) const routeId = useMatches()[1].id const routeChildren = router.routes[0].children?.find((value) => value.id === routeId)?.children const pathname = useLocation().pathname + + const hideScrollbarRef = useRef(null) + + const [navbarHidden, setNavbarHidden] = useState(true) + const [preventScroll, setPreventScroll] = useState(false) + useEffect(() => { setNavbarHidden(false) }, [pathname]) + const handleOnWheel = useCallback((event: React.WheelEvent) => { + console.log(event) + }, []) + + const handleOnScroll = useCallback((event: React.UIEvent) => { + console.log(event) + }, []) + return ( <> - +
@@ -61,6 +85,7 @@ const MainFramework: React.FC = () => { diff --git a/vite.config.ts b/vite.config.ts index f6f8d1e..a4acaba 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -35,11 +35,6 @@ export default defineConfig({ from: 'react-router', imports: ['RouteObject'], type: true - }, - { - from: 'react', - imports: ['PropsWithChildren', 'RefObject'], - type: true } ], From 201d6485e9dd21e9b9df11ea89a1c82e9802b44a Mon Sep 17 00:00:00 2001 From: FatttSnake Date: Mon, 11 Sep 2023 18:31:58 +0800 Subject: [PATCH 2/5] Fix can not remove event listener bug --- src/components/HideScrollbar.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/HideScrollbar.tsx b/src/components/HideScrollbar.tsx index 815f7fd..76a3714 100644 --- a/src/components/HideScrollbar.tsx +++ b/src/components/HideScrollbar.tsx @@ -44,20 +44,19 @@ const HideScrollbar = forwardRef((prop const [horizontalScrollbarWidth, setHorizontalScrollbarWidth] = useState(0) const { isPreventScroll, ..._props } = props - - const handleDefaultWheel = (event: WheelEvent) => { + const handleDefaultWheel = useCallback((event: WheelEvent) => { event.preventDefault() - } + }, []) - const handleDefaultTouchmove = (event: TouchEvent) => { + const handleDefaultTouchmove = useCallback((event: TouchEvent) => { event.preventDefault() - } + }, []) - const handleDefaultClickMiddleMouseButton = (event: MouseEvent) => { + const handleDefaultClickMiddleMouseButton = useCallback((event: MouseEvent) => { if (event.button === 1) { event.preventDefault() } - } + }, []) const handleDefaultKeyDown = (event: KeyboardEvent) => { if ( From be12a7a75350fd729c850e95e5140a210038312c Mon Sep 17 00:00:00 2001 From: FatttSnake Date: Mon, 11 Sep 2023 18:32:49 +0800 Subject: [PATCH 3/5] Add auto scroll (still has problem) --- src/components/Home.tsx | 109 ++++++++++++++++++++---------------- src/pages/MainFramework.tsx | 17 +----- 2 files changed, 64 insertions(+), 62 deletions(-) diff --git a/src/components/Home.tsx b/src/components/Home.tsx index 5d967de..f52f509 100644 --- a/src/components/Home.tsx +++ b/src/components/Home.tsx @@ -8,13 +8,15 @@ import { MainFrameworkContext } from '@/pages/MainFramework.tsx' const Home: React.FC = () => { const { hideScrollbarRef, - navbarHiddenState: { navbarHidden, setNavbarHidden } + navbarHiddenState: { setNavbarHidden }, + preventScrollState: { setPreventScroll } } = useContext(MainFrameworkContext) const fitFullScreenRef = useRef(null) const pathname = useLocation().pathname const [slogan, setSlogan] = useState('') const [sloganType, setSloganType] = useState(true) + const [showSlogan, setShowSlogan] = useState(true) const typeText = '/* 因为热爱 所以折腾 */' if (sloganType) { @@ -35,59 +37,72 @@ const Home: React.FC = () => { }, 50) } - const hideScrollbarDOM = hideScrollbarRef.current - const scrollListener = useCallback(() => { - if ( - hideScrollbarDOM && - fitFullScreenRef.current && - hideScrollbarDOM.getY() < fitFullScreenRef.current?.offsetHeight - ) { - if (!navbarHidden) { - setNavbarHidden(true) - } - } else { - if (navbarHidden) { + useEffect(() => { + setTimeout(() => { + setNavbarHidden(true) + }) + }, [setNavbarHidden]) + + useEffect(() => { + setNavbarHidden(true) + }, [pathname, setNavbarHidden]) + + const handleScrollToDown = () => { + hideScrollbarRef.current?.scrollY(fitFullScreenRef.current?.offsetHeight ?? 0) + } + + const handleScrollToTop = () => { + hideScrollbarRef.current?.scrollY(0) + } + + const handleWheel = (event: React.WheelEvent) => { + if (showSlogan) { + if (event.deltaY > 0) { + handleScrollToDown() + setPreventScroll(false) + setShowSlogan(false) setNavbarHidden(false) } + } else { + console.log( + hideScrollbarRef.current?.getY() + ' ' + fitFullScreenRef.current?.offsetHeight + ) + if ( + hideScrollbarRef.current && + fitFullScreenRef.current && + hideScrollbarRef.current.getY() < fitFullScreenRef.current.offsetHeight + ) { + console.log('上翻') + setPreventScroll(true) + setShowSlogan(true) + setNavbarHidden(true) + handleScrollToTop() + } } - }, [hideScrollbarDOM, navbarHidden, setNavbarHidden]) - - useEffect(() => { - hideScrollbarDOM?.removeEventListener('scroll', scrollListener) - hideScrollbarDOM?.addEventListener('scroll', scrollListener) - return () => { - hideScrollbarDOM?.removeEventListener('scroll', scrollListener) - } - }, [hideScrollbarDOM, scrollListener]) - - useEffect(() => { - scrollListener() - }, [pathname, scrollListener]) - - const handleScrollDown = () => { - hideScrollbarRef.current?.scrollY(fitFullScreenRef.current?.offsetHeight ?? 0) } return ( <> - - -
-
FatWeb
- - {slogan || <> } - -
-
- -
-
-
- - +
+ + +
+
FatWeb
+ + {slogan || <> } + +
+
+ +
+
+
+ + +
) } diff --git a/src/pages/MainFramework.tsx b/src/pages/MainFramework.tsx index d885588..6e1bd62 100644 --- a/src/pages/MainFramework.tsx +++ b/src/pages/MainFramework.tsx @@ -35,28 +35,15 @@ const MainFramework: React.FC = () => { const hideScrollbarRef = useRef(null) const [navbarHidden, setNavbarHidden] = useState(true) - const [preventScroll, setPreventScroll] = useState(false) + const [preventScroll, setPreventScroll] = useState(true) useEffect(() => { setNavbarHidden(false) }, [pathname]) - const handleOnWheel = useCallback((event: React.WheelEvent) => { - console.log(event) - }, []) - - const handleOnScroll = useCallback((event: React.UIEvent) => { - console.log(event) - }, []) - return ( <> - +
From 28ff5c55347aac9fe21a7c990d94f2bda113121f Mon Sep 17 00:00:00 2001 From: FatttSnake Date: Mon, 11 Sep 2023 23:22:27 +0800 Subject: [PATCH 4/5] Optimize FitCenter and FitFullScreen --- src/components/FitCenter.tsx | 7 +++++-- src/components/FitFullScreen.tsx | 12 ++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/components/FitCenter.tsx b/src/components/FitCenter.tsx index ea15292..4db55b9 100644 --- a/src/components/FitCenter.tsx +++ b/src/components/FitCenter.tsx @@ -1,10 +1,13 @@ import React from 'react' import '@/assets/css/fit-center.scss' -const FitCenter: React.FC = (props) => { +const FitCenter: React.FC< + React.DetailedHTMLProps, HTMLDivElement> +> = (props) => { + const { className, ..._props } = props return ( <> -
{props.children}
+
) } diff --git a/src/components/FitFullScreen.tsx b/src/components/FitFullScreen.tsx index 2dbebbe..3a05f1b 100644 --- a/src/components/FitFullScreen.tsx +++ b/src/components/FitFullScreen.tsx @@ -1,21 +1,25 @@ import React from 'react' import '@/assets/css/fit-fullscreen.scss' -interface FitFullscreenProps extends React.PropsWithChildren { +interface FitFullscreenProps + extends React.DetailedHTMLProps, HTMLDivElement> { zIndex?: number backgroundColor?: string } const FitFullScreen = forwardRef((props, ref) => { + const { zIndex, backgroundColor, className, style, ..._props } = props return ( <>
{props.children}
From f4425db53721a6e4b241a5731ab0a21dc086200b Mon Sep 17 00:00:00 2001 From: FatttSnake Date: Mon, 11 Sep 2023 23:22:51 +0800 Subject: [PATCH 5/5] Optimize scroll in Home --- src/components/Home.tsx | 37 +++++++++---------------------------- src/pages/MainFramework.tsx | 2 +- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/src/components/Home.tsx b/src/components/Home.tsx index f52f509..afde976 100644 --- a/src/components/Home.tsx +++ b/src/components/Home.tsx @@ -12,11 +12,9 @@ const Home: React.FC = () => { preventScrollState: { setPreventScroll } } = useContext(MainFrameworkContext) const fitFullScreenRef = useRef(null) - const pathname = useLocation().pathname const [slogan, setSlogan] = useState('') const [sloganType, setSloganType] = useState(true) - const [showSlogan, setShowSlogan] = useState(true) const typeText = '/* 因为热爱 所以折腾 */' if (sloganType) { @@ -40,44 +38,27 @@ const Home: React.FC = () => { useEffect(() => { setTimeout(() => { setNavbarHidden(true) + setPreventScroll(true) }) - }, [setNavbarHidden]) - - useEffect(() => { - setNavbarHidden(true) - }, [pathname, setNavbarHidden]) + }, [setNavbarHidden, setPreventScroll]) const handleScrollToDown = () => { hideScrollbarRef.current?.scrollY(fitFullScreenRef.current?.offsetHeight ?? 0) + setNavbarHidden(false) } const handleScrollToTop = () => { hideScrollbarRef.current?.scrollY(0) + setNavbarHidden(true) } const handleWheel = (event: React.WheelEvent) => { - if (showSlogan) { - if (event.deltaY > 0) { - handleScrollToDown() - setPreventScroll(false) - setShowSlogan(false) - setNavbarHidden(false) - } + if (event.deltaY > 0) { + handleScrollToDown() + setNavbarHidden(false) } else { - console.log( - hideScrollbarRef.current?.getY() + ' ' + fitFullScreenRef.current?.offsetHeight - ) - if ( - hideScrollbarRef.current && - fitFullScreenRef.current && - hideScrollbarRef.current.getY() < fitFullScreenRef.current.offsetHeight - ) { - console.log('上翻') - setPreventScroll(true) - setShowSlogan(true) - setNavbarHidden(true) - handleScrollToTop() - } + handleScrollToTop() + setNavbarHidden(true) } } diff --git a/src/pages/MainFramework.tsx b/src/pages/MainFramework.tsx index 6e1bd62..54e77b8 100644 --- a/src/pages/MainFramework.tsx +++ b/src/pages/MainFramework.tsx @@ -35,7 +35,7 @@ const MainFramework: React.FC = () => { const hideScrollbarRef = useRef(null) const [navbarHidden, setNavbarHidden] = useState(true) - const [preventScroll, setPreventScroll] = useState(true) + const [preventScroll, setPreventScroll] = useState(false) useEffect(() => { setNavbarHidden(false)