React实现图片悬停放大镜效果同时支持onLoad与onError事件的问题
解决方案
方案1:基于现有react-image-magnifiers组件扩展(无需更换组件)
GlassMagnifier 本身没有暴露onError事件,我们可以通过提前预加载图片的方式自行处理加载成功/失败逻辑,再决定是否渲染放大镜组件,完全复用原有圆形放大镜效果:
import { GlassMagnifier } from "react-image-magnifiers"; import { useState, useEffect, memo } from "react"; export const Image = memo(({imgSrc = "https://some-link"}) => { const [loadState, setLoadState] = useState('loading'); // 可选值loading/success/error const onLoad = () => { console.log("inside load"); // 执行业务逻辑 }; const onError = err => { console.log("inside error"); // 执行业务逻辑 }; // 预加载图片处理加载状态 useEffect(() => { const img = new Image(); img.src = imgSrc; img.onload = () => { setLoadState('success'); onLoad(); }; img.onerror = (err) => { setLoadState('error'); onError(err); }; return () => { img.onload = null; img.onerror = null; } }, [imgSrc]); if(loadState === 'loading') return <div>图片加载中</div> if(loadState === 'error') return <div>图片加载失败占位</div> return ( <GlassMagnifier imageAlt="certificate-preview" imageSrc={imgSrc} className="image" magnifierSize="35%" /> ); });
方案2:自定义轻量圆形放大镜组件(无第三方依赖)
如果不想依赖第三方包,可以自己实现圆形放大镜效果,所有事件完全可控:
组件代码
import { useState, useRef, memo } from "react"; import "./magnifier.css"; export const CustomMagnifierImage = memo(({ src, alt = "preview", width = 200, height = 300, magnifyScale = 2, onLoad, onError }) => { const [showMagnifier, setShowMagnifier] = useState(false); const [magnifierPos, setMagnifierPos] = useState({ x: 0, y: 0 }); const imgRef = useRef(null); const magnifierSize = width * 0.35; // 35%的放大镜尺寸,可自行调整 const handleMouseMove = (e) => { const rect = imgRef.current.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; // 限制放大镜不超出图片边界 const safeX = Math.max(0, Math.min(x, width)); const safeY = Math.max(0, Math.min(y, height)); setMagnifierPos({ x: safeX, y: safeY }); }; return ( <div className="magnifier-wrapper" style={{ width, height }}> {/* 原图直接绑定onLoad/onError事件 */} <img ref={imgRef} src={src} alt={alt} onLoad={onLoad} onError={onError} onMouseEnter={() => setShowMagnifier(true)} onMouseLeave={() => setShowMagnifier(false)} onMouseMove={handleMouseMove} className="original-image" style={{ width, height }} /> {/* 圆形放大镜 */} {showMagnifier && ( <div className="magnifier-glass" style={{ width: magnifierSize, height: magnifierSize, left: `${magnifierPos.x}px`, top: `${magnifierPos.y}px`, backgroundImage: `url(${src})`, backgroundSize: `${width * magnifyScale}px ${height * magnifyScale}px`, backgroundPosition: `-${magnifierPos.x * magnifyScale - magnifierSize/2}px -${magnifierPos.y * magnifyScale - magnifierSize/2}px`, }} /> )} </div> ); });
对应样式magnifier.css
.magnifier-wrapper { position: relative; } .original-image { display: block; object-fit: contain; } .magnifier-glass { position: absolute; border: 2px solid #fff; border-radius: 50%; cursor: none; transform: translate(-50%, -50%); pointer-events: none; box-shadow: 0 0 10px rgba(0,0,0,0.3); }
内容的提问来源于stack exchange,提问作者nikita kumari
相关产品推荐
相关产品推荐

