import { useEffect, useState, useRef } from 'react' import { ArrowUp } from 'lucide-react' import { cn } from '@/lib/utils' import { Button } from '@/components/ui/button' export function BackToTop() { const [progress, setProgress] = useState(0) const [visible, setVisible] = useState(false) const scrollerRef = useRef(null) useEffect(() => { const handleScroll = (e: Event) => { const target = e.target as HTMLElement // 简单的启发式:如果是主要滚动容器(通常高度较大) // 我们假设页面中主要的滚动区域是高度最大的那个,或者就是当前触发滚动的这个 // 只要它有足够的滚动空间 if (target.scrollHeight > target.clientHeight + 100) { scrollerRef.current = target const scrollTop = target.scrollTop const height = target.scrollHeight - target.clientHeight const scrolled = height > 0 ? (scrollTop / height) * 100 : 0 setProgress(scrolled) setVisible(scrollTop > 300) } } // 使用捕获阶段监听所有滚动事件,因为 scroll 事件不冒泡 window.addEventListener('scroll', handleScroll, { capture: true, passive: true }) return () => window.removeEventListener('scroll', handleScroll, { capture: true }) }, []) const scrollToTop = () => { scrollerRef.current?.scrollTo({ top: 0, behavior: 'smooth' }) } // SVG 环形进度条参数 const radius = 18 const circumference = 2 * Math.PI * radius const strokeDashoffset = circumference - (progress / 100) * circumference return (
) }