安装 react-cropper
npm install --save react-cropper //或者
yarn add react-cropper
1. jsx文件
import { useState } from 'react';
import Cropper from 'react-cropper' // 引入Cropper
import 'cropperjs/dist/cropper.css' // 引入Cropper对应的css
import './App.css';
const MAX_FILE_SIZE = 5 * 1024 * 1024 // 文件最大限制为5M
function App() {
const [hooksModalVisible, setHooksModalVisible] = useState(false) // 裁剪图片
const [hooksModalFile, setHooksModalFile] = useState(null) // 选取的img文件
const [hooksResultImgUrl, setHooksResultImgUrl] = useState(null)// 裁剪后的img
const handleHooksFileChange = e => {
const file = e.target.files[0]
if (file) {
if (file.size <= MAX_FILE_SIZE) {
setHooksModalFile(file)
setHooksModalVisible(true)
} else {
console.log('文件过大')
}
}
}
return (
<div className="App">
<h1>图片裁剪组件</h1>
<div className="half-area">
<label className="upload-input-label">
<span>(hooks形式的component)添加图片</span>
{/* 获取本地文件,如果不想要这个按钮样式,可以直接给透明度为0 */}
<input
type="file"
accept="image/jpeg,image/jpg,image/png"
className="base-upload-input"
onChange={handleHooksFileChange}
/>
</label>
{/* 最终裁剪好的图片 */}
<div className="img-container">
{hooksResultImgUrl && (
<img
className="img"
src={hooksResultImgUrl}
alt="classResultImgUrl"
/>
)}
</div>
</div>
{/* 裁剪框 */}
{hooksModalVisible && (
<HooksCropperModal
uploadedImageFile={hooksModalFile}
onClose={() => {
setHooksModalVisible(false)
}}
onSubmit={setHooksResultImgUrl}
/>
)}
</div>
);
}
{/* 裁剪框组件 */}
function HooksCropperModal({ uploadedImageFile, onClose, onSubmit }) {
const [src, setSrc] = useState(null) // 被选中的待裁剪文件的src
const cropperRef = useRef(null) // 标记Cropper,会用到自带的方法将裁剪好的img的url进行转义
useEffect(() => {
const fileReader = new FileReader()// 拿到文件
fileReader.onload = e => {
const dataURL = e.target.result
setSrc(dataURL)
}
fileReader.readAsDataURL(uploadedImageFile)
}, [uploadedImageFile])
const handleSubmit = useCallback(() => {
// let filename = uploadedImageFile.name
console.log('正在上传图片')
// TODO: 这里可以尝试修改上传图片的尺寸
const dataUrl = cropperRef.current.cropper.getCroppedCanvas().toDataURL()
// async blob => {
// // 创造提交表单数据对象
// const formData = new FormData()
// // 添加要上传的文件
// formData.append('file', blob, filename)
// 提示开始上传 (因为demo没有后端server, 所以这里代码我注释掉了, 这里是上传到服务器并拿到返回数据的代码)
// this.setState({submitting: true})
// 上传图片
// const resp = await http.post(url, formData)
// 拿到服务器返回的数据(resp)
// console.log(resp)
// 提示上传完毕
// this.setState({submitting: false})
//把选中裁切好的的图片传出去
onSubmit(dataUrl)
// 关闭弹窗
onClose()
// }
}, [onClose, onSubmit])
return (
<div className="hooks-cropper-modal">
<div className="modal-panel">
<div className="cropper-container-container">
<div className="cropper-container">
<Cropper
src={src}
className="cropper"
ref={cropperRef}
// Cropper.js options
viewMode={1}
rotatable={true}// 旋转图片
zoomable={false}
aspectRatio={1} // 固定为1:1 可以自己设置比例, 默认情况为自由比例
guides={false}
preview=".cropper-preview"
/>
</div>
<div className="preview-container">
<div className="cropper-preview" />
</div>
</div>
<div className="button-row">
<div className="" onClick={()=>{
cropperRef.current.cropper.rotate(90);// 顺时针旋转,若逆时针,则为-90
}}>
旋转
</div>
<div className="submit-button" onClick={handleSubmit}>
点击提交
</div>
</div>
</div>
</div>
)
}
{/* props属性的限制规则 */}
HooksCropperModal.propTypes = {
uploadedImageFile: PropTypes.object.isRequired, // 1. 限制类型 2.必要性
onClose: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired
}
export default App;
2. css文件
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.submit-button {
padding: 0 20px;
height: 100%;
color: #383838;
font-size: 14px;
}
.cropper-container-container {
flex: 1;
display: flex;
align-items: stretch;
justify-content: space-between;
height: 100%;
}
.cropper-container {
flex: 0 0 600px;
margin-right: 20px;
}
.cropper {
width: 100%;
height: 100%;
}
.preview-container {
flex: 1;
display: flex;
align-items: flex-end;
}
.cropper-preview {
width: 180px;
height: 180px;
overflow: hidden;
border: 1px solid #383838;
}