使用react-cropper实现图片裁剪

安装 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;
}