使用React-Cropper-Pro实现图片裁切压缩上传

在前端开发的使用o实缩上过程中, 我们经常遇到文件上传或者图片上传的需求, 有些场景中可能还会要求上传图片后对图片进行裁切, 压缩. 对于不想加班的程序员来说, 第一要义就是使用斯第三方库. 虽然像我们熟悉的antd, element等库提供了上传组件:

image.png

但是这些第三方UI库一方面体积比较庞大, 不够轻量, 另一方面不支持裁切, 压缩等功能, 所以还是需要自己实现或者整合第三方库实现, 当然 antd 提供了一个图片裁切的库 antd-img-crop, 但是使用上极度“难受”(受限), 无法自由裁切图片, 同时也无法提供压缩能力:

所以这个方案也直接pass.  最终为了实现想要的效果,我还是决定牺牲自己, 手动实现一个支持上传裁切并压缩的组件, 并取名为react-cropper-pro。

react-cropper-pro 使用介绍

react-cropper-pro是现图一款简单轻量的图片上传 + 裁切 + 压缩 组件, 不依赖antd / element等第三方UI, 快速实现图片处理相关操作, 底层依赖react-cropper。

安装yarn add react-cropper-pro使用import CropperPro from react-cropper-pro;

export default () =>

defaultImg=""

onChange={ (file) => console.log(file)}

onDel={ (image) => console.log(remove,片裁 image)}

/>;

image.png

API介绍

技术实现

技术上主要有以下几个核心点:

实现文件上传组件样式(主要是覆盖原生input[file]的“纯洁UI”)。实现突图片裁切。切压实现图片压缩。使用o实缩上包装成react组件并发布到npm。现图

接下来和大家简单介绍一下实现细节.

1、片裁实现文件上传组件样式

我们都知道元素的切压input文件上传组件采用的云服务器默认样式非常简陋, 所以我们需要通过某种方式替换原生样式, 这里和大家分享一下我实现的方式。

其实很简单,使用o实缩上 就是用定位的方式将一个同样大小的div覆盖在input上面, 然后把让div事件穿透, 能响应input的事件即可. 核心代码如下:

</div>

其次就是需要用户在上传完图片之后, 图片能展示在上传区域, 如下:

这块的完整代码如下:

{

cropData ? : +

}

{

!!cropData && ✕

}

</div>2、实现突图片裁切

图片裁切这里我采用了 react-cropper 这个库,现图 虽然不能直接实现图片上传, 但是它的图片裁切能力还是很强大的. 我们需要实现的效果是图片上传后会出现上传弹窗, 显示裁切区域, 如下:

这里弹窗的实现我采用了React-Dom的createPortal API, 它可以实现弹窗dom挂载在指定的容器上, 很多组件库的组件比如抽屉, Modal, DropDown都采用了类似的实现原理, 我之前也写了一篇文章来介绍如何使用 createPortal 的, 感兴趣的朋友可以学习参考一下:

​​《精通react/vue组件设计》之配合React Portals实现一个功能强大的抽屉(Drawer)组件。网站模板​​

这块的片裁核心源码可以参考github仓库对应的第134行。

文件路径如下: https://github.com/MrXujiang/react-cropper-pro/tree/main/src/crop。切压

3、使用o实缩上实现图片压缩

图片压缩这块主要是现图基于产品业务场景来设计, 这里我分了4个档:

不压缩高中低

如下:

这一块主要是利用了canvas和 cropper 的能力, 我们通过控制canvas对象的宽高比例, 和canvas提供的toBlob 来实现图片的压缩, 核心代码如下:​

if (typeof cropper !== "undefined") {

setCropData(cropper.getCroppedCanvas().toDataURL());

const rate = 1 / (4 - imgLevel);

const { width, height } = cropper.getCropBoxData();

cropper.getCroppedCanvas({

width: width * rate,

height: height * rate,

imageSmoothingQuality: imgLevelValueMap[imgLevel],

fillColor: transparent,

}).toBlob((blob: Blob) => {

if(blob) {

const time = Date.now();

let croppedFile:any = new File([blob], fileRef.current.name, {

type: fileRef.current.type,

lastModified: Date.now(),

});

croppedFile.uid = time;

onChange && onChange(croppedFile)

}else {

new Error(图片裁切失败);

}

}, fileRef.current.type, rate)

}

当然有关 canvas 的toBlob API不熟悉的朋友可以移步MDN:

https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/toBlob。

4、片裁包装成react组件并发布到npm

最后再来看看应用场景, 目前 react-cropper-pro 已经应用于H5-Dooring 可视化搭建平台中, 来实现图片更精准的控制:

感兴趣的朋友可以体验一下, 当然还有很多内容平台, 因为有富文本或者md等编辑器的写作能力, 所以也会涉及到对图片的控制, 所以这些都是 react-cropper-pro 的应用领域。

滇ICP备2023000592号-31