一、组件概述
ImageMagnifier 是一个基于 React 实现的图片局部放大预览组件,核心功能为:
- 展示 500×500px 原始图片
- 鼠标悬浮时显示 100×100px 半透明遮罩(以鼠标为中心)
- 右侧同步预览遮罩覆盖区域的图片细节(放大 5 倍)
- 支持边界限制,避免遮罩移出图片容器
- 状态驱动视图,符合 React 开发规范
二、核心特性
| 特性 | 说明 |
|---|---|
| 🖱️ 鼠标跟随 | 遮罩以鼠标为中心,跟随鼠标移动 |
| 🎯 边界限制 | 遮罩不会超出 500×500px 图片容器 |
| 🔍 局部放大 | 右侧预览区将遮罩区域放大 5 倍展示 |
| 🎨 样式可配置 | 所有样式均通过对象定义,便于修改 |
| ♻️ 可复用性 x | 所有样式均通过对象定义,便于修改 |
| ⚡ 性能优化 | 遮罩设置 pointer-events: none,避免鼠标事件抖动 |
三、安装与引入
1. 组件文件创建
在项目中新建 ImageMagnifier.jsx 文件,粘贴以下完整代码:
javascript
import { useState, useRef, useEffect } from 'react';
const ImageMagnifier = ({ imgUrl }) => {
// 容器、遮罩、预览区 DOM 引用
const containerRef = useRef(null);
const maskRef = useRef(null);
const previewRef = useRef(null);
// 控制遮罩和预览区显示/隐藏
const [visible, setVisible] = useState(false);
// 图片加载完成后初始化预览区背景
useEffect(() => {
const img = new Image();
img.src = imgUrl;
img.onload = () => {
if (previewRef.current) {
// 设置预览区背景图 + 放大 5 倍(500/100)
previewRef.current.style.backgroundImage = `url(${imgUrl})`;
previewRef.current.style.backgroundSize = '2500px 2500px';
}
};
}, [imgUrl]);
// 鼠标移动:更新遮罩位置 + 预览区显示内容
const handleMouseMove = (e) => {
if (!containerRef.current || !maskRef.current) return;
const rect = containerRef.current.getBoundingClientRect();
// 鼠标在容器内的坐标
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// 遮罩尺寸 100px,以鼠标为中心
const maskWidth = 100;
const maskHeight = 100;
let maskX = x - maskWidth / 2;
let maskY = y - maskHeight / 2;
// 限制遮罩不超出容器
maskX = Math.max(0, Math.min(maskX, 500 - maskWidth));
maskY = Math.max(0, Math.min(maskY, 500 - maskHeight));
// 更新遮罩位置
maskRef.current.style.left = `${maskX}px`;
maskRef.current.style.top = `${maskY}px`;
// 更新预览区背景位置(放大 5 倍)
if (previewRef.current) {
previewRef.current.style.backgroundPosition = `-${maskX * 5}px -${maskY * 5}px`;
}
};
return (
<div style={containerStyle}>
{/* 左侧原图容器 */}
<div
ref={containerRef}
style={imgContainerStyle}
onMouseMove={handleMouseMove}
onMouseEnter={() => setVisible(true)}
onMouseLeave={() => setVisible(false)}
>
<img src={imgUrl} alt="原图" style={imgStyle} />
{/* 鼠标遮罩层 */}
<div
ref={maskRef}
style={{
...maskStyle,
display: visible ? 'block' : 'none',
}}
/>
</div>
{/* 右侧细节预览区 */}
<div
ref={previewRef}
style={{
...previewStyle,
display: visible ? 'block' : 'none',
}}
/>
</div>
);
};
// 样式配置
const containerStyle = {
display: 'flex',
gap: '20px',
padding: '20px',
};
const imgContainerStyle = {
position: 'relative',
width: '500px',
height: '500px',
border: '1px solid #eee',
overflow: 'hidden',
cursor: 'crosshair',
};
const imgStyle = {
width: '100%',
height: '100%',
objectFit: 'cover',
};
const maskStyle = {
position: 'absolute',
width: '100px',
height: '100px',
background: 'rgba(255, 255, 255, 0.3)',
border: '1px solid rgba(0,0,0,0.2)',
pointerEvents: 'none',
};
const previewStyle = {
width: '500px',
height: '500px',
border: '1px solid #eee',
backgroundRepeat: 'no-repeat',
};
export default ImageMagnifier;
2. 组件使用
在需要使用放大镜的页面中引入并使用组件:
javascript
import ImageMagnifier from './ImageMagnifier';
function App() {
return (
<div className="App">
<h1>图片放大镜预览</h1>
{/* 传入图片地址即可 */}
<ImageMagnifier
imgUrl="https://p.qqan.com/up/2021-3/16153651644385966.jpg"
/>
</div>
);
}
export default App;
四、API 说明
Props
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| imgUrl | string | ✅ | 原始图片的 URL 地址(支持本地路径 / 网络地址) |
样式配置(可修改)
所有样式均以 JS 对象形式定义,可直接修改对应属性:
containerStyle:整体容器样式(控制左右布局)imgContainerStyle:左侧图片容器样式(宽高、边框、鼠标样式)imgStyle:内部图片样式(适配方式)maskStyle:遮罩层样式(尺寸、透明度、边框)previewStyle:右侧预览区样式(宽高、边框)
五、核心实现原理
1. 坐标计算
- 鼠标坐标 :通过
getBoundingClientRect()计算鼠标在图片容器内的相对坐标 (x, y) - 遮罩位置 :
maskX = x - 50、maskY = y - 50,实现鼠标在遮罩中心 - 边界限制 :通过
Math.max()和Math.min()确保遮罩不会超出500×500px容器
2. 放大预览
- 预览区宽高与容器一致(500px),遮罩尺寸为 100px,因此放大比例为 5
- 预览区背景图尺寸设置为
2500px × 2500px(500×5) - 背景位置通过
backgroundPosition: -maskX*5, -maskY*5实现与遮罩区域同步
3. React 状态管理
- 使用
useState控制遮罩和预览区的显示 / 隐藏 - 使用
useRef操作 DOM 元素(容器、遮罩、预览区) - 使用
useEffect监听 imgUrl 变化,初始化预览区背景图
六、常见问题与优化
1. 图片加载闪烁
- 原因:图片未加载完成时预览区样式未初始化
- 解决方案:在
useEffect中监听img.onload事件,确保图片加载完成后再设置背景样式
2. 鼠标移动抖动
- 原因:遮罩层拦截了鼠标事件,导致
mousemove触发异常 - 解决方案:给遮罩层添加
pointer-events: none,让鼠标事件穿透到下层容器
3. 自定义放大比例
- 修改遮罩尺寸(如改为 80px),同时修改预览区背景尺寸和
backgroundPosition计算比例 - 示例:遮罩 80px → 放大比例 = 500/80 = 6.25 → 背景尺寸 = 500×6.25 = 3125px
4. 移动端适配
- 新增触摸事件监听(
touchstart/touchmove/touchend) - 计算触摸点坐标时替换
clientX/clientY为touches[0].clientX/touches[0].clientY
七、示例效果
- 鼠标未悬浮:仅显示 500×500px 原始图片
- 鼠标悬浮:显示 100×100px 半透明遮罩,右侧同步展示遮罩区域的放大细节
- 鼠标移出:遮罩和预览区自动隐藏

结语
该组件开箱即用,可直接集成到 React 项目中,也可根据业务需求进行二次开发(如修改样式、调整放大比例、适配移动端等)。