react-image-crop
react-image-crop 是react响应式图片裁剪的一个工具包,能做到裁剪区域,裁剪宽高比限制等等。
npm地址:https://www.npmjs.com/package/react-image-crop
阅读前须知
版本的不同,在使用时有不同的表现,也可能造成使用失败。
本文中基于版本:8.6.2
安装
npm
1 | npm install react-image-crop --save |
CDN
1 | <script src="//i2.wp.com/unpkg.com/react-image-crop/dist/ReactCrop.min.js"></script> |
注意,当使用
组件使用
1 2 3 4 5 6 7 8 | <ReactCrop src={imageurl} crop={crop} ruleOfThirds onImageLoaded={this.onImageLoaded} onComplete={this.onCropComplete} onChange={this.onCropChange} /> |
属性解释:
src:图片路径
crop:裁剪相关配置 参考地址:https://www.npmjs.com/package/react-image-crop#crop-required
ruleOfThirds:裁剪区域三分规则默认false;
ruleOfThirds为false时:

ruleOfThirds为true时(注意图中裁剪区域的九宫格):

onImageLoaded: 图片加载时的回调函数,返回image对象;
onComplete:裁剪区域调整大小、拖动、微调之后的回调,返回当前裁剪对象;
onChange:裁剪区域调整大小、拖动、微调时的回调,返回当前裁剪对象;官网中的提示:请注意,您必须实现此回调并更新您的裁剪状态,否则什么都不会改变!
更多属性参考
获取到的裁剪区域保存为图片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | // 组件的onComplete事件 onCropComplete = crop => { this.makeClientCrop(crop); }; // 调用getCroppedImg函数获取裁剪图片信息 async makeClientCrop(crop) { if (this.imageRef && crop.width && crop.height) { const croppedImageUrl = await this.getCroppedImg( this.imageRef, crop, 'newFile.jpeg' ); /* * croppedImageUrl: {url,blob,crop} * @url:图片文件对象的DOMString url * @blob: 图片文件的类文件对象 * @crop: 裁剪参数 */ } // 裁剪区域转图片的处理 getCroppedImg(image, crop, fileName) { const canvas = document.createElement('canvas'); const scaleX = image.naturalWidth / image.width; const scaleY = image.naturalHeight / image.height; canvas.width = crop.width; canvas.height = crop.height; const ctx = canvas.getContext('2d'); ctx.drawImage( image, crop.x * scaleX, crop.y * scaleY, crop.width * scaleX, crop.height * scaleY, 0, 0, crop.width, crop.height ); return new Promise((resolve, reject) => { canvas.toBlob(blob => { if (!blob) { //reject(new Error('Canvas is empty')); console.error('Canvas is empty'); return; } blob.name = fileName; window.URL.revokeObjectURL(this.fileUrl); this.fileUrl = window.URL.createObjectURL(blob); resolve({url:this.fileUrl,blob,crop}); }, 'image/jpeg'); }); } |
官方完整示例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | import ReactDOM from "react-dom"; import React, { PureComponent } from "react"; import ReactCrop from "react-image-crop"; import "react-image-crop/dist/ReactCrop.css"; import "./App.css"; class App extends PureComponent { state = { src: null, crop: { unit: "%", width: 30, aspect: 16 / 9 } }; onSelectFile = e => { if (e.target.files && e.target.files.length > 0) { const reader = new FileReader(); reader.addEventListener("load", () => this.setState({ src: reader.result }) ); reader.readAsDataURL(e.target.files[0]); } }; // If you setState the crop in here you should return false. onImageLoaded = image => { this.imageRef = image; }; onCropComplete = crop => { this.makeClientCrop(crop); }; onCropChange = (crop, percentCrop) => { // You could also use percentCrop: // this.setState({ crop: percentCrop }); this.setState({ crop }); }; async makeClientCrop(crop) { if (this.imageRef && crop.width && crop.height) { const croppedImageUrl = await this.getCroppedImg( this.imageRef, crop, "newFile.jpeg" ); this.setState({ croppedImageUrl }); } } getCroppedImg(image, crop, fileName) { const canvas = document.createElement("canvas"); const scaleX = image.naturalWidth / image.width; const scaleY = image.naturalHeight / image.height; canvas.width = crop.width; canvas.height = crop.height; const ctx = canvas.getContext("2d"); ctx.drawImage( image, crop.x * scaleX, crop.y * scaleY, crop.width * scaleX, crop.height * scaleY, 0, 0, crop.width, crop.height ); return new Promise((resolve, reject) => { canvas.toBlob(blob => { if (!blob) { //reject(new Error('Canvas is empty')); console.error("Canvas is empty"); return; } blob.name = fileName; window.URL.revokeObjectURL(this.fileUrl); this.fileUrl = window.URL.createObjectURL(blob); resolve(this.fileUrl); }, "image/jpeg"); }); } render() { const { crop, croppedImageUrl, src } = this.state; return ( <div className="App"> <div> <input type="file" accept="image/*" onChange={this.onSelectFile} /> </div> {src && ( <ReactCrop src={src} crop={crop} ruleOfThirds onImageLoaded={this.onImageLoaded} onComplete={this.onCropComplete} onChange={this.onCropChange} /> )} {croppedImageUrl && ( <img alt="Crop" style={{ maxWidth: "100%" }} src={croppedImageUrl} /> )} </div> ); } } ReactDOM.render(<App />, document.getElementById("root")); |
在线编辑地址:https://codesandbox.io/s/react-image-crop-demo-with-classes-7jxc0?file=/src/index.js:0-2838