Bootstrap

Antd - 上传图片 & 裁剪图片

本地上传方法【input type=“file”】

js操作本地文件,通过input type="file"选择本地文件

1、FileReader

const fileInput = document.createElement('input');
fileInput.type = 'file'; // js创建file类型input
fileInput.click(); // 触发
fileInput?.addEventListener('change', (event) => {
    const file = event.target?.files[0]; // target返回事件的目标节点,现返回的是input节点本身
    const reader = new FileReader(); // FileReader 只能访问用户明确选择的文件内容
    reader.readAsDataURL(file); // readAsDataURL:开始读取指定的 Blob 中的内容。一旦完成,result 属性中将包含一个表示文件数据的 data: URL
    reader.addEventListener('load', () => {
        console.log(reader.result);
    });
});

// 用户触发行为点击上传文件
<input type="file" id="file-input">
const fileInput = document.getElementById('file-input');
// 后续同上上传代码

上传的文件想要不同格式时,可以使用FileReader不同的实例方法获取:

  • readAsArrayBuffer() - 标识文件数据的ArrayBuffer对象在这里插入图片描述

  • readAsBinaryString() - 表示文件中原始二进制数据的字符串在这里插入图片描述

  • readAsDataURL() - 表示文件数据的data:URL在这里插入图片描述

  • readAsText() - 表示所读取的文件内容的字符串,可以制定可选的编码名称在这里插入图片描述

2、FormData

const fileInput = document.createElement('input');
fileInput.type = 'file'; 
fileInput.click(); 
fileInput?.addEventListener('change', (event) => {
    const file = event.target?.files[0];
    const files = new FormData();
    files.append('file', file);
    console.log('FormData-',files)
});

console结果
使用场景:FormData 对象用以将数据编译成键值对,以便用XMLHttpRequest来发送数据。其主要用于发送表单数据,但亦可用于发送带键数据 (keyed data),而独立于表单使用。如果表单enctype属性设为 multipart/form-data,则会使用表单的submit()方法来发送数据,从而,发送数据具有同样形式。

3、FileReader & FormData 区别

FormData 和 FileReader 是 JavaScript 中用于处理文件上传和读取的两个对象,区别如下:

  • 作用不同:
  •  FormData:主要用于构建一个表单数据对象,可以将文件或其他数据以键值对的形式添加到该对象中,然后通过 AJAX 请求发送给服务器。例如在上述代码中,新建了一个 FormData 对象,并将一个文件添加到了 'file' 字段。
    
  •  FileReader:主要用于读取文件内容,可以读取文件的内容,如文本、Base64 编码、二进制数据等,并在读取完成后触发相应的事件。FileReader 对象提供了一系列方法,如 readAsText()、readAsDataURL() 等,用于读取文件的内容。
    
  • 使用场景:
  •  FormData:通常用于需要上传文件的场景,如表单提交、图片上传等。
    
  •  FileReader:通常用于需要读取文件内容的场景,如文件预览(如图片预览、音频播放等)、文件加密、文件下载等
    

upload组件【antd】

默认接口上传:

  • 使用action属性拼接完整的请求接口地址,eg:action={baseURL + ‘/v1/object/uploadicon’}
  • 使用默认上传时注意,需要将token携带到请求头属性中
  • 在这里插入图片描述

自定义接口上传:【取消默认上传接口】

  • 首先取消默认上传时的接口,在beforeUpload方法return false,来阻止默认上传。即【Upload上传有个action的坑,就是你选择文件之后自动调用地址然后就会执行上传接口,如果不取消会一直有一个失败请求,但不影响主体流程】在这里插入图片描述

  • 上传前文件格式校验

  • 在上传文件校验或onchange方法中获取上传的文件,进行自定义接口请求传递

 const props: UploadProps = {
        name: 'file',
        multiple: false,
        showUploadList: false,
       	async beforeUpload(file) {
            setImgLoading(true)
            const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg' || file.type === 'image/webp';
            const isLt2M = file.size / 1024 / 1024 < 2;
            const isSize = await new Promise<boolean>((resolve) => {
                const _URL = window.URL || window.webkitURL;
                const img = new Image();
                img.onload = () => {
                    const valid = img.width / img.height === 1;
                    resolve(valid);
                };
                img.src = _URL.createObjectURL(file);
            });

            if (!isJpgOrPng) {
                message.error('请上传png、jpeg、jpg、webp格式图片');
            } else if (!isLt2M) {
                message.error('上传图片大小不超过2M');
            } else if (!isSize) {
                message.error('上传图片比例建议1:1');
            }
            
            if (!isJpgOrPng || !isLt2M || !isSize) {
                return Upload.LIST_IGNORE;
            }

            return false; // 因为自定义接口请求,没有设置action值,所以关闭默认上传事件
        },
     	onChange(file){
            const files = new FormData();
            files.append('file', file.file);
            // 将files上传给后端接口处理
        }
    };

antd的upload组件beforeUpload还有个比较坑的地方

beforeUpload校验不通过return false的话,onchange中还是会接收到file上传文件信息
在这里插入图片描述

解决方法:在beforeUpload校验不通过时return Upload.LIST_IGNORE 阻止文件上传,此时onChange就接收不到不合校验规则的file了

在这里插入图片描述

upload结合裁剪

1、antd官方裁剪组件

在这里插入图片描述

裁剪组件是配合 antd-img-crop 实现上传前裁切图片,可以进行属性动态配置

在这里插入图片描述

上传前裁剪图片官方使用:

import React, { useState } from 'react';
import { Upload } from 'antd';
import type { GetProp, UploadFile, UploadProps } from 'antd';
import ImgCrop from 'antd-img-crop';

type FileType = Parameters<GetProp<UploadProps, 'beforeUpload'>>[0];

const App: React.FC = () => {
  const [fileList, setFileList] = useState<UploadFile[]>([
    {
      uid: '-1',
      name: 'image.png',
      status: 'done',
      url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
    },
  ]);

  const onChange: UploadProps['onChange'] = ({ fileList: newFileList }) => {
    setFileList(newFileList);
  };

  const onPreview = async (file: UploadFile) => {
    let src = file.url as string;
    if (!src) {
      src = await new Promise((resolve) => {
        const reader = new FileReader();
        reader.readAsDataURL(file.originFileObj as FileType);
        reader.onload = () => resolve(reader.result as string);
      });
    }
    const image = new Image();
    image.src = src;
    const imgWindow = window.open(src);
    imgWindow?.document.write(image.outerHTML);
  };

  return (
    <ImgCrop rotationSlider>
      <Upload
        action="https://660d2bd96ddfa2943b33731c.mockapi.io/api/upload"
        listType="picture-card"
        fileList={fileList}
        onChange={onChange}
        onPreview={onPreview}
      >
        {fileList.length < 5 && '+ Upload'}
      </Upload>
    </ImgCrop>
  );
};

export default App;

2、antd裁剪图片二次开发

antd官方提供的裁剪可以设置裁剪的比例、形状,放大缩小、旋转按钮显隐等,但一般实际开发时需求与官方例子会略有差异,需要进行裁剪组件源码理解以及二次开发

开发需求要求(重新上传、任务对比框、重新打开裁剪框等):
在这里插入图片描述
将antd封装的官方裁剪组件代码拉取到项目中进行再次开发

组件源码目录
在这里插入图片描述
具体的二次开发步骤后续更新 ~

结合form表单使用:

上传图片结合form表单使用时,页面的图片字段检测不到Upload上传图片获取的url数据变化导致图片更新问题,如何实现检测数据变化

有不对的地方请大佬们指正 ^^

;