fix:解决拖拽问题

This commit is contained in:
zhongyidian committed 2025-10-20 17:50:42 +08:00
1 parent ce06ad0214
commit 6367014e1f
34 files changed
+1712 -397

No files matched your search

+176
View File
@@ -0,0 +1,176 @@
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<HTMLImageElement>(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 (
<div
className={clsx(
"inline-block",
button &&
"cursor-pointer transition-all duration-300 hover:scale-105 hover:brightness-110",
className
)}
style={{ width, height }}
onClick={onClick}
>
{/* 加载占位符 */}
{isLoading && placeholder && (
<div
className="w-full h-full bg-gray-200 flex items-center justify-center"
style={{
backgroundImage: `url(${placeholder})`,
backgroundSize: "cover",
}}
>
<div className="animate-pulse bg-gray-300 rounded w-full h-full" />
</div>
)}
{/* 加载中状态 */}
{isLoading && !placeholder && (
<div className="w-full h-full bg-gray-200 flex items-center justify-center">
<div className="animate-pulse bg-gray-300 rounded w-full h-full" />
</div>
)}
{/* 错误状态 */}
{hasError && (
<div className="w-full h-full bg-gray-100 flex items-center justify-center">
<div className="text-gray-400 text-center">
<svg
className="w-8 h-8 mx-auto mb-2"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"
/>
</svg>
<p className="text-sm">图片加载失败</p>
</div>
</div>
)}
{/* 实际图片 */}
<img
ref={imgRef}
src={imageSrc}
alt={alt}
style={imageStyle}
loading={loading}
draggable={draggable}
onLoad={handleLoad}
onError={handleError}
className={clsx(
"transition-opacity duration-300",
isLoaded ? "opacity-100" : "opacity-0"
)}
/>
</div>
);
}