ReactCrop组件裁剪预览无法在视口正常渲染
问题原因
ReactCrop预览无法正常渲染是四个典型问题导致的:
- 初始
crop配置缺少必填的unit字段,裁剪区域宽高计算值异常,导致预览层尺寸为0或直接溢出视口 - 高版本react-image-crop(v10+)废弃了直接通过
onImageLoaded回传图片DOM的用法,没有正确绑定图片ref会导致裁剪层无法挂载 - 未给图片和裁剪组件设置最大宽高约束,大分辨率原图加载后会直接超出视口范围,视觉上表现为预览不显示
- 裁剪逻辑中canvas宽高被重复赋值,且缺少空值判断,会触发JS错误中断渲染
修复方案
直接替换为以下可运行代码,核心调整点:
- 补全
crop初始配置,设置默认裁剪区域占比,避免初始尺寸计算异常 - 用
useRef绑定图片DOM,通过onComplete回调获取最终裁剪参数,适配高版本API - 给图片和裁剪容器添加最大宽高限制,保证内容始终在视口内渲染
- 修复canvas尺寸计算逻辑,增加裁剪前的空值判断,避免运行时报错
- 保留官方样式引入,保证裁剪遮罩、选框样式正常加载
import { useState, useRef } from 'react'; import ReactCrop from 'react-image-crop'; import 'react-image-crop/dist/ReactCrop.css'; function App() { const [src, setSrc] = useState(null); const [crop, setCrop] = useState({ unit: '%', width: 80, aspect: 16 / 9 }); const [completedCrop, setCompletedCrop] = useState(null); const imgRef = useRef(null); const [output, setOutput] = useState(null); const selectImage = (file) => { setOutput(null); setSrc(URL.createObjectURL(file)); }; const cropImageNow = () => { if (!imgRef.current || !completedCrop?.width || !completedCrop?.height) return; const image = imgRef.current; const canvas = document.createElement('canvas'); const scaleX = image.naturalWidth / image.width; const scaleY = image.naturalHeight / image.height; const ctx = canvas.getContext('2d'); const pixelRatio = window.devicePixelRatio || 1; canvas.width = Math.floor(completedCrop.width * scaleX * pixelRatio); canvas.height = Math.floor(completedCrop.height * scaleY * pixelRatio); ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); ctx.imageSmoothingQuality = 'high'; ctx.drawImage( image, completedCrop.x * scaleX, completedCrop.y * scaleY, completedCrop.width * scaleX, completedCrop.height * scaleY, 0, 0, completedCrop.width * scaleX, completedCrop.height * scaleY, ); setOutput(canvas.toDataURL('image/jpeg', 0.9)); }; return ( <div style={{ padding: '20px', maxWidth: '1000px', margin: '0 auto' }}> <input type="file" accept="image/*" onChange={(e) => e.target.files?.[0] && selectImage(e.target.files[0])} /> <br /><br /> {src && ( <div> <ReactCrop crop={crop} onChange={setCrop} onComplete={setCompletedCrop} style={{ maxWidth: '100%' }} > <img ref={imgRef} src={src} alt="裁剪预览" style={{ maxWidth: '100%', maxHeight: '70vh' }} /> </ReactCrop> <br /> <button onClick={cropImageNow} style={{ padding: '8px 16px' }}>确认裁剪</button> <br /><br /> </div> )} {output && ( <div> <h4>裁剪结果</h4> <img src={output} alt="裁剪结果" style={{ maxWidth: '100%', border: '1px solid #eee' }} /> </div> )} </div> ); } export default App;
补充说明:如果使用v9及以下旧版本react-image-crop,可以保留原有
onImageLoaded写法,但建议升级到最新稳定版,旧版本存在移动端触摸裁剪偏移、高DPI屏幕裁剪结果模糊的已知问题。
内容的提问来源于stack exchange,提问作者CSS-Romeo
相关产品推荐
相关产品推荐

