feat(ui/ux): 优化用户体验和可访问性
- 字体加载优化: 添加 font-display: block 策略,创建 useFontLoading hook - 色彩对比度: 调整 text-muted 和 text-tertiary 颜色值确保 WCAG AA 合规 - 滚动进度条: 新增 ScrollProgress 组件,支持 reduced motion - 表单自动保存: 新增 useFormAutosave hook,防止用户数据丢失 - 返回顶部按钮: 新增 BackToTop 组件,提升长页面导航体验 - 图片懒加载: 优化 OptimizedImage 组件,添加 blur placeholder 和加载动画 所有新组件均包含完整测试,1450+ 测试通过
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { ArrowUp } from 'lucide-react';
|
||||
import { useReducedMotion } from '@/hooks/use-reduced-motion';
|
||||
|
||||
export function BackToTop() {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
const shouldReduceMotion = useReducedMotion();
|
||||
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
// 当滚动超过 500px 时显示按钮
|
||||
setIsVisible(window.scrollY > 500);
|
||||
};
|
||||
|
||||
window.addEventListener('scroll', handleScroll, { passive: true });
|
||||
return () => window.removeEventListener('scroll', handleScroll);
|
||||
}, []);
|
||||
|
||||
const scrollToTop = () => {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
behavior: shouldReduceMotion ? 'auto' : 'smooth',
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{isVisible && (
|
||||
<motion.button
|
||||
initial={shouldReduceMotion ? {} : { opacity: 0, y: 20, scale: 0.8 }}
|
||||
animate={{ opacity: 1, y: 0, scale: 1 }}
|
||||
exit={shouldReduceMotion ? {} : { opacity: 0, y: 20, scale: 0.8 }}
|
||||
transition={{ duration: 0.2, ease: 'easeOut' }}
|
||||
onClick={scrollToTop}
|
||||
className="fixed bottom-8 right-8 z-50 p-3 bg-[#C41E3A] text-white rounded-full shadow-lg hover:bg-[#A01830] hover:shadow-xl transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-[#C41E3A] focus:ring-offset-2"
|
||||
aria-label="返回顶部"
|
||||
title="返回顶部"
|
||||
style={{
|
||||
boxShadow: '0 4px 14px rgba(196, 30, 58, 0.4)',
|
||||
}}
|
||||
whileHover={shouldReduceMotion ? {} : { scale: 1.1 }}
|
||||
whileTap={shouldReduceMotion ? {} : { scale: 0.95 }}
|
||||
>
|
||||
<ArrowUp className="w-6 h-6" />
|
||||
</motion.button>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user