antd+react实现html图片预览结果

[复制链接]
发表于 2025-9-19 09:06:33 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
import { Image } from ‘antd’;
import { useEffect, useRef, useState } from ‘react’;
import styles from ‘./index.module.less’;
interface PreviewHtmlWithImagesProps {
htmlContent: string;
}
const PreviewHtmlWithImages: React.FC = ({ htmlContent }) => {
const containerRef = useRef(null);
const [imageSrc, setImageSrc] = useState(’’);
const [visible, setVisible] = useState(false);
const [isZoomed, setIsZoomed] = useState(false);
const actionsRef = useRef(null);
// 新增:用于跟踪拖动状态
const isDraggingRef = useRef(false);
const startPosRef = useRef({ x: 0, y: 0 });
const processedHtml = htmlContent.replace(
/<img([^>]*)src="’"’>/gi,
(match, beforeSrc, src, afterSrc) => {
if (/data-src=/i.test(match)) return match;
return <img${beforeSrc}src="${src}" data-src="${src}" class="preview-image"${afterSrc}>;
},
);
useEffect(() => {
const images: any = containerRef.current?.querySelectorAll(’.preview-image’);
images?.forEach((img: HTMLImageElement) => {
const clickHandler = () => {
const src = img.getAttribute(‘data-src’);
setImageSrc(src || ‘’);
setVisible(true);
setIsZoomed(false);
};
  1.   img.style.cursor = 'zoom-in';
  2.   img.addEventListener('click', clickHandler);
  3.   return () => {
  4.     img.removeEventListener('click', clickHandler);
  5.     img.style.cursor = '';
  6.   };
  7. });
复制代码
}, [processedHtml]);
useEffect(() => {
if (!visible) {
setIsZoomed(false);
return;
}
  1. const previewContent: HTMLImageElement | null = document.querySelector(
  2.   '.ant-image-preview-content',
  3. );
  4. const previewImg: HTMLImageElement | null = document.querySelector(
  5.   '.ant-image-preview-img',
  6. ) as HTMLImageElement | null;
  7. const imgWrapper: HTMLImageElement | null = document.querySelector(
  8.   '.ant-image-preview-img-wrapper',
  9. );
  10. if (!previewContent || !previewImg || !imgWrapper) return;
  11. // 阻止滚轮事件
  12. const handleWheel = (e: WheelEvent) => {
  13.   e.preventDefault();
  14.   e.stopPropagation();
  15. };
  16. // 鼠标按下事件
  17. const handleMouseDown = (e: MouseEvent) => {
  18.   isDraggingRef.current = false;
  19.   startPosRef.current = { x: e.clientX, y: e.clientY };
  20. };
  21. // 鼠标移动事件
  22. const handleMouseMove = (e: MouseEvent) => {
  23.   // 移动超过5px才认为是拖动
  24.   if (
  25.     Math.abs(e.clientX - startPosRef.current.x) > 5 ||
  26.     Math.abs(e.clientY - startPosRef.current.y) > 5
  27.   ) {
  28.     isDraggingRef.current = true;
  29.   }
  30. };
  31. // 鼠标松开事件
  32. const handleMouseUp = () => {
  33.   // 如果是拖动操作,则设置一个短暂的时间窗口忽略点击
  34.   if (isDraggingRef.current) {
  35.     setTimeout(() => {
  36.       isDraggingRef.current = false;
  37.     }, 100);
  38.   }
  39. };
  40. // 点击事件处理
  41. const handleClick = (e: MouseEvent) => {
  42.   // 如果是拖动后的点击,则忽略
  43.   if (isDraggingRef.current) {
  44.     e.preventDefault();
  45.     e.stopPropagation();
  46.     return;
  47.   }
  48.   if (!actionsRef.current) return;
  49.   setIsZoomed((prev) => {
  50.     const newState = !prev;
  51.     previewImg.style.cursor = newState ? 'grab' : 'zoom-in';
  52.     if (newState) {
  53.       actionsRef.current.onZoomIn();
  54.     } else {
  55.       actionsRef.current.onZoomOut();
  56.     }
  57.     return newState;
  58.   });
  59. };
  60. previewImg.style.cursor = isZoomed ? 'grab' : 'zoom-in';
  61. previewContent.addEventListener('wheel', handleWheel, { passive: false });
  62. imgWrapper.addEventListener('mousedown', handleMouseDown);
  63. imgWrapper.addEventListener('mousemove', handleMouseMove);
  64. imgWrapper.addEventListener('mouseup', handleMouseUp);
  65. previewImg.addEventListener('click', handleClick);
  66. return () => {
  67.   previewContent.removeEventListener('wheel', handleWheel);
  68.   imgWrapper.removeEventListener('mousedown', handleMouseDown);
  69.   imgWrapper.removeEventListener('mousemove', handleMouseMove);
  70.   imgWrapper.removeEventListener('mouseup', handleMouseUp);
  71.   previewImg.removeEventListener('click', handleClick);
  72.   previewImg.style.cursor = '';
  73. };
复制代码
}, [visible, isZoomed]);
return (
<>

<div className={styles.documentation} dangerouslySetInnerHTML={{ __html: processedHtml }} />

<Image
src={imageSrc}
rootClassName=“preview-images”
preview={{
visible,
src: imageSrc,
movable: isZoomed,
onVisibleChange: (vis) => setVisible(vis),
toolbarRender: (_: any, { actions }: any) => {
actionsRef.current = actions;
return null;
},
scaleStep: 0.5,
maxScale: 5,
}}
/>
</>
);
};
export default PreviewHtmlWithImages;
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表