import { useState, useRef, useEffect } from "react"; import { clsx } from "clsx"; interface ImageProps { src: string; alt?: string; className?: string; width?: number | string; height?: number | string; objectFit?: "cover" | "contain" | "fill" | "none" | "scale-down"; objectPosition?: string; loading?: "lazy" | "eager"; placeholder?: string; fallback?: string; onLoad?: () => void; onError?: () => void; onClick?: () => void; draggable?: boolean; quality?: number; blur?: boolean; button?: boolean; } export default function Image({ src, alt, className, width, height, objectFit = "cover", objectPosition = "center", loading = "lazy", placeholder, fallback, onLoad, onError, onClick, draggable = false, quality = 80, blur = false, button = false, }: ImageProps) { const [imageSrc, setImageSrc] = useState(src); const [isLoading, setIsLoading] = useState(true); const [hasError, setHasError] = useState(false); const [isLoaded, setIsLoaded] = useState(false); const imgRef = useRef(null); // 处理图片加载 const handleLoad = () => { setIsLoading(false); setIsLoaded(true); setHasError(false); onLoad?.(); }; // 处理图片错误 const handleError = () => { setIsLoading(false); setHasError(true); if (fallback && imageSrc !== fallback) { setImageSrc(fallback); } onError?.(); }; // 重置状态当src改变时 useEffect(() => { if (src !== imageSrc) { setImageSrc(src); setIsLoading(true); setHasError(false); setIsLoaded(false); } }, [src, imageSrc]); // 懒加载处理 useEffect(() => { if (loading === "lazy" && imgRef.current) { const observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { setImageSrc(src); observer.disconnect(); } }); }, { threshold: 0.1 } ); observer.observe(imgRef.current); return () => observer.disconnect(); } }, [loading, src]); const imageStyle = { width: width, height: height, objectFit, objectPosition, filter: blur ? "blur(4px)" : "none", transition: "filter 0.3s ease", }; return (
{/* 加载占位符 */} {isLoading && placeholder && (
)} {/* 加载中状态 */} {isLoading && !placeholder && (
)} {/* 错误状态 */} {hasError && (

图片加载失败

)} {/* 实际图片 */} {alt}
); }