Files
carrotskin/src/components/ScrollToTop.tsx

66 lines
2.0 KiB
TypeScript
Raw Normal View History

'use client';
import { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
export default function ScrollToTop() {
const [showScrollTop, setShowScrollTop] = useState(false);
useEffect(() => {
let ticking = false;
const handleScroll = () => {
if (!ticking) {
window.requestAnimationFrame(() => {
const currentScrollY = window.scrollY;
// 显示返回顶部按钮滚动超过300px
setShowScrollTop(currentScrollY > 300);
ticking = false;
});
ticking = true;
}
};
window.addEventListener('scroll', handleScroll, { passive: true });
return () => window.removeEventListener('scroll', handleScroll);
}, []);
const scrollToTop = () => {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
};
return (
<AnimatePresence>
{showScrollTop && (
<motion.button
initial={{ opacity: 0, scale: 0.8, y: 20 }}
animate={{ opacity: 1, scale: 1, y: 0 }}
exit={{ opacity: 0, scale: 0.8, y: 20 }}
transition={{ duration: 0.2, ease: 'easeOut' }}
onClick={scrollToTop}
className="fixed bottom-6 right-6 w-12 h-12 bg-gradient-to-br from-orange-400/70 to-amber-300/70 hover:from-orange-600/70 hover:to-orange-700/70 text-white rounded-full shadow-lg hover:shadow-xl transition-all duration-200 flex items-center justify-center z-40 group"
whileHover={{ scale: 1.1, y: -2 }}
whileTap={{ scale: 0.9 }}
>
<svg
className="w-5 h-5 transition-transform duration-200 group-hover:-translate-y-0.5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M5 10l7-7m0 0l7 7m-7-7v18"
/>
</svg>
</motion.button>
)}
</AnimatePresence>
);
}