/** * 图片预览模态框组件 * * 支持点击图片放大查看,带缩放、拖拽功能 * 支持直接渲染 React 组件(用于显示 canvas 内容) */ import React, { useState, useRef, useEffect } from 'react'; import { X, RotateCw, Download } from 'lucide-react'; interface ImagePreviewModalProps { imageUrl?: string; isOpen: boolean; onClose: () => void; title?: string; downloadFileName?: string; renderContent?: () => React.ReactNode; // 自定义渲染内容 } const ImagePreviewModal: React.FC = ({ imageUrl, isOpen, onClose, title = '图片预览', downloadFileName = 'image.png', renderContent }) => { const [scale, setScale] = useState(1); const [rotation, setRotation] = useState(0); const [position, setPosition] = useState({ x: 0, y: 0 }); const [isDragging, setIsDragging] = useState(false); const [dragStart, setDragStart] = useState({ x: 0, y: 0 }); const imageRef = useRef(null); // 重置状态 useEffect(() => { if (isOpen) { setScale(1); setRotation(0); setPosition({ x: 0, y: 0 }); } }, [isOpen]); // ESC 键关闭 useEffect(() => { const handleEsc = (e: KeyboardEvent) => { if (e.key === 'Escape' && isOpen) { onClose(); } }; window.addEventListener('keydown', handleEsc); return () => window.removeEventListener('keydown', handleEsc); }, [isOpen, onClose]); // 阻止背景滚动 useEffect(() => { if (isOpen) { document.body.style.overflow = 'hidden'; } else { document.body.style.overflow = ''; } return () => { document.body.style.overflow = ''; }; }, [isOpen]); if (!isOpen) return null; // 缩放控制 const handleZoomIn = () => setScale(prev => Math.min(prev + 0.25, 5)); const handleZoomOut = () => setScale(prev => Math.max(prev - 0.25, 0.25)); const handleResetZoom = () => { setScale(1); setPosition({ x: 0, y: 0 }); }; // 旋转控制 const handleRotate = () => setRotation(prev => (prev + 90) % 360); // 下载图片 const handleDownload = () => { if (!imageUrl) return; const link = document.createElement('a'); link.href = imageUrl; link.download = downloadFileName; link.target = '_blank'; document.body.appendChild(link); link.click(); document.body.removeChild(link); }; // 鼠标拖拽 const handleMouseDown = (e: React.MouseEvent) => { if (scale > 1) { setIsDragging(true); setDragStart({ x: e.clientX - position.x, y: e.clientY - position.y }); } }; const handleMouseMove = (e: React.MouseEvent) => { if (isDragging && scale > 1) { setPosition({ x: e.clientX - dragStart.x, y: e.clientY - dragStart.y }); } }; const handleMouseUp = () => { setIsDragging(false); }; // 鼠标滚轮缩放 const handleWheel = (e: React.WheelEvent) => { e.preventDefault(); if (e.deltaY < 0) { handleZoomIn(); } else { handleZoomOut(); } }; return (
{/* 工具栏 */}

{title}

{/* 旋转 */} {/* 下载 */} {imageUrl && ( )} {/* 关闭 */}
{/* 图片容器 */}
e.stopPropagation()} onMouseDown={handleMouseDown} onMouseMove={handleMouseMove} onMouseUp={handleMouseUp} onMouseLeave={handleMouseUp} onWheel={handleWheel} style={{ cursor: scale > 1 ? (isDragging ? 'grabbing' : 'grab') : 'default' }} > {renderContent ? ( // 自定义内容渲染(用于 canvas 等)
{renderContent()}
) : imageUrl ? ( // 普通图片渲染 预览 ) : null}
); }; export default ImagePreviewModal;