import React, { useCallback, useEffect, useState } from 'react' import Cropper from "react-cropper"; import "cropperjs/dist/cropper.css"; import { Button, Col, Form, InputNumber, message, Radio, Row, Spin, Upload } from 'antd'; import Modal from 'antd/lib/modal/Modal'; import { RcFile } from 'antd/lib/upload'; import { InboxOutlined } from '@ant-design/icons' const { Dragger } = Upload import { compressAccurately } from 'image-conversion'; import { blobToBase64 } from '@/utils/compress' interface Props { width?: number,//初始裁剪框宽 height?: number,//初始裁剪框高 imgSize?: { width: number, height: number, size: number }, disabled?: boolean, // 是否禁止传入 btnName?: string | JSX.Element//按钮名称 isChangeCropperSize?: boolean, // 是否可以改变裁剪框大小 isLaunch?: boolean, // 是否是在落地页上传 isCropper?: boolean, // 是否需要裁剪 isJudgeSize?: boolean, // 是否判断图片宽高与传入的裁剪框宽高 图片大小需要大于裁剪框大小 callback?: (imgData: any) => void//裁剪后图片的数据 } /**图片裁剪 * @param width 初始裁剪框宽 * @param height 初始高度 * @param btnName 按钮名称 * @param disabled 是否禁止传入 * @param isLaunch 是否是在落地页上传 * @param isCropper 是否需要裁剪 * @param callback 裁剪后图片的数据的回调函数 * @param isJudgeSize 是否判断图片宽高与传入的裁剪框宽高 图片大小需要大于裁剪框大小 需传入width和height */ export const Demo = (props: Props) => { let { isJudgeSize = false, isChangeCropperSize = false, isLaunch = false, isCropper = false, disabled = false, imgSize } = props const [image, setImage] = useState('');//初始图片 const [visible, setVisible] = useState(false) const [cropper, setCropper] = useState();//实例 const [loading, setLoading] = useState(false) const [detail, setDetail] = useState<{ width: number, height: number, rotate: number }>({ width: props?.width || 800, height: props?.height || 800, rotate: 0 });//设置数据 /**关闭 */ const cancel = useCallback(() => { setVisible(false) setCropper(undefined) setImage('') }, []) /**获取裁剪数据*/ const getCropData = () => { if (typeof cropper !== "undefined") { props?.callback && props?.callback(cropper.getCroppedCanvas().toDataURL('image/jpeg')) cancel() } }; /**数值变化重置实例 */ useEffect(() => { if (typeof cropper !== "undefined") { cropper.setData(detail); } }, [cropper, detail]); useEffect(() => { if (visible && cropper) { setTimeout(() => { cropper.reset() if (props?.width) { cropper.setData({ width: props?.width, height: props?.height }) } }, 200) } }, [visible, cropper]) return { { }} beforeUpload={(file: RcFile, FileList: RcFile[]): any => { setLoading(true) let img: any = new Image(); let _URL = window.URL || window.webkitURL; img.onload = function (e: any) { if (isJudgeSize) { if (!props?.width || !props?.height) { console.error('请传入"width"与"height"'); setLoading(false) return } else if (props?.width < this.width || props?.height < this.height) { message.error(`传入的图片大小不符, 图片大小${this.width}*${this.height}, 需要图片大小${props.width}*${props.height}`) setLoading(false) return } } const reader = new FileReader(); reader.onload = async () => { let size = imgSize?.size || 307200 if (isCropper) { setImage(reader.result as any); setLoading(false) } else { if (imgSize && (imgSize?.width === 800 || imgSize?.width === 640 || imgSize?.width === 960)) { if (imgSize?.width !== this.width || imgSize?.height !== this.height) { message.error(`请上传${imgSize?.width} * ${imgSize?.height}尺寸图片`) setLoading(false) return } } else if (imgSize?.width === 750) { if (imgSize?.width !== this.width || this.height > 1536) { message.error(`请上传${imgSize?.width} * <1536尺寸图片`) setLoading(false) return } } if (size === 307200 && file?.size > size) { // 大于300kb进入压缩 let bole = await compressAccurately(file, 250) if (bole?.size > 300000) { bole = await compressAccurately(file, 200) } if (bole?.size > 300000) { bole = await compressAccurately(file, 150) } if (bole?.size > 300000) { bole = await compressAccurately(file, 100) } let newFile = await blobToBase64(bole) message.warning({ content: '选择的图片大于300KB,图片已压缩', duration: 3 }) props?.callback && props?.callback(newFile); setLoading(false) return } else if (size === 81920 && file?.size > size) { let bole = await compressAccurately(file, 80) if (bole?.size > 80000) { bole = await compressAccurately(file, 60) } if (bole?.size > 80000) { bole = await compressAccurately(file, 40) } let newFile = await blobToBase64(bole) message.warning({ content: '选择的图片大于80KB,图片已压缩', duration: 3 }) props?.callback && props?.callback(newFile); setLoading(false) return } props?.callback && props?.callback(reader.result); setLoading(false) } }; reader.readAsDataURL(file); if (isCropper) { setLoading(false) setVisible(true) } } img.src = _URL.createObjectURL(file); }} > { props?.btnName ? props?.btnName : <>

单击或拖动文件到此区域以上载

支持jpg,png...

}
} {visible && {/* */} } >
{ setCropper(instance); }} />

Preview

{ setDetail({ ...detail, width: e.target.value, height: 800 }) }} value={detail.width}> 800 750 640 {detail.width === 800 ? { setDetail({ ...detail, height: e.target.value }) }} value={detail.height}> 800 640 450 : detail.width === 640 ? { setDetail({ ...detail, height: e.target.value }) }} value={detail.height}> 800 : { setDetail({ ...detail, height: e || 0 }) }} /> }
} }; export default Demo;