Update scroll to top

This commit is contained in:
DefectingCat
2022-12-12 15:24:29 +08:00
parent 7954c974da
commit a43cd50166
3 changed files with 39 additions and 20 deletions

View File

@ -1,6 +1,6 @@
import clsx from 'clsx';
import Button from 'components/RUA/Button';
import { memo } from 'react';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { FiChevronUp } from 'react-icons/fi';
const BackToTop = () => {
@ -11,6 +11,24 @@ const BackToTop = () => {
});
};
const [showTop, setShowTop] = useState(false);
const lastScrollTop = useRef(0);
const handleScroll = useCallback(() => {
const st = window.pageYOffset || document.documentElement.scrollTop;
if (st > lastScrollTop.current || st <= 0) {
// downscroll
setShowTop(false);
} else {
// upscroll
setShowTop(true);
}
lastScrollTop.current = st <= 0 ? 0 : st;
}, []);
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [handleScroll]);
return (
<>
<Button
@ -18,7 +36,9 @@ const BackToTop = () => {
className={clsx(
'!p-3 fixed',
'right-4 bottom-4',
'lg:right-8 lg:bottom-8'
'lg:right-8 lg:bottom-8',
'transition-all duration-300',
showTop ? 'visible scale-100' : 'invisible scale-0'
)}
>
<FiChevronUp className="w-6 h-6" />

View File

@ -1,5 +1,4 @@
import dynamic from 'next/dynamic';
import { useCallback, useEffect, useState } from 'react';
const Footer = dynamic(() => import('components/Footer'));
const HeadBar = dynamic(() => import('components/NavBar'));
@ -10,28 +9,12 @@ type Props = {
};
const MainLayout = ({ children }: Props) => {
const [showTop, setShowTop] = useState(false);
const handleScroll = useCallback(() => {
const target = document.documentElement || document.body;
const scrollableHeight = target.scrollHeight - target.clientHeight;
const scrollHeight = target.scrollTop;
if (scrollHeight / scrollableHeight >= 0.1) {
setShowTop(true);
} else {
setShowTop(false);
}
}, []);
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [handleScroll]);
return (
<>
<HeadBar />
{children}
<Footer />
{showTop && <BackToTop />}
<BackToTop />
</>
);
};

View File

@ -102,3 +102,19 @@ export const getMousePosition = (e: MouseEvent | globalThis.TouchEvent) => {
y: e.touches[0].clientY,
};
};
type Debounce = {
<T extends unknown[], R>(fn: (...arg: T) => R, ms: number): (
this: unknown,
...arg: T
) => void;
};
export const debounce: Debounce = (fn, ms) => {
let timer: NodeJS.Timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, ms);
};
};