移动端上传+裁剪

977 阅读3分钟

一、背景

  • 背景:因业务需要改版个人中心,并兼容移动端,头像上传之前只是在pc端存在,移动端没有入口,现需增加
  • 技术定位:react + react-cropper

前期调研移动端上传+裁剪现有方案都存在哪些,调研的方案有

  1. react-easy-crop: github.com/ValentinH/r…
  2. react-image-crop:github.com/DominicTobi…
  3. react-avatar-editor:www.npmjs.com/package/rea…
  4. react-cropper: github.com/react-cropp…

最终选择的是react-avatar-editor,后期和UI沟通裁剪都涉及了哪些功能,以及页面的展示,遂有转成了react-cropper

上传这里本来pc端用的是antd-upload,后来因为要直接关联到相册,便使用了antd-mobile中imageUploader (这里还需要研究一下,关联相册和文件的区别)

二、实现

上传

import { ImageUploader } from 'antd-mobile';

<ImageUploader
  // value={fileList}
  preview={false}
  // beforeUpload={beforeUpload}
  // onChange={handleUploadChange}
  // maxCount={1}
  accept={'image/*'}
  upload={handleUpload}
  // beforeUpload={() => closePopup()}
>
  <div className={styles.upload_text}>
    上传头像
  </div>
</ImageUploader>


const handleUpload = async (file: File) => {
  // console.log('file---', file);
  // console.log('URL.createObjectURL(file)', URL.createObjectURL(file));
 
  if (file && file.size && file.size > 10 * 1024 * 1024) {
    return;
  }
  if (file) {
   
    setFileImage(URL.createObjectURL(file) as any);
    setModalVisible(true);
  }

  
  return {
    url: URL.createObjectURL(file),
  };
};

代码里面有一些注释的属性,因需求本身功能原因未使用到

handleUpload 方法 接受的是一个文件对象,包含上传的文件信息,可通过File 来进行逻辑判断和重写文件信息

URL.createObjectURL(file) 该方式可以将文件对象转换成二进制文件地址 url地址

mdn地址

将当前获取的地址 传递 剪裁组件中


裁剪

裁剪使用的组件是 react-cropper Api 文档就不过多赘述 前面有gitHub链接

  • 主要的功能点
    1. 支持手动缩放
    2. 支持选择裁剪区域
    3. 裁剪区域必须为正方形
const cropperRef = useRef<HTMLImageElement>(null);

<div className={styles.content}>
  {fileImage && (
    <Cropper
      src={fileImage}
      aspectRatio={1}
      viewMode={0}
      style={{
        height: '100%',
        width: '100%',
        backgroundColor: '#ffffff',
      }}
      // background={false}
      center={false}
      // initialAspectRatio={1}
      guides={false}
      crop={onCrop}
      ref={cropperRef}
      crossOrigin="use-credentials"
      minCropBoxHeight={10}
      minCropBoxWidth={10}
    />
  )}
</div>

const onCrop = () => {
  const imageElement: any = cropperRef?.current;
  const cropper: any = imageElement?.cropper;
  const dataUrl = cropper.getCroppedCanvas().toDataURL();
  setImageUrl(dataUrl);
};

简单介绍一下 代码中的属性

  • Src 对应上传文件的二进制(blob)地址

  • aspectRatio 图片的宽高比

  • viewMode 视图模式 0 代表沿用canvas的视图

  • Center 代表是否居中显示

  • guides:裁剪框上方的虚线

  • crop 裁剪后的回调

  • crossOrigin 跨域配置

  • minCropBoxHeight 最小裁剪高度

  • minCropBoxWidth 最小裁剪宽度

onCrop 是cropper 裁剪后的回调函数 回调中可以通过获取当前cropper对象来获得裁剪后图片的地址

当点页面确定时,将裁剪后的图片进行上传 调取上传接口


const handleSaveCropImg = async () => {
  setLoading(true);
  const res = await uploadImageToPath('/avatar', imageUrl);
  if (res?.success && res?.data && user?.studentProfile?.id) {
    const saveRes = await updateAvatar(user?.studentProfile?.id, res.data);
    if (saveRes?.success) {
      await fetchUser();
    }
  }
  setLoading(false);
};

上传接口返回值便是裁剪后图片的 云平台存储地址

有意思的方法

图片地址转化为base64

什么场景会用到这个方法呢

当服务端要求上传的图片路径是base64的时候,我们拿到文件的路径是一个相对路径或者二进制路径时 需要做一层转换

三、总结

  • 调研方案一定要基于UI设计的功能 不然可能选择的插件不是最合适的

  • 调研时 多去尝试插件库的demo 这样才能确定是否能正常满足需要

  • 确定方案时 需要确认当前方案对应的热度和问题数以及迭代速度