目录
本地上传方法【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)
});
使用场景: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数据变化导致图片更新问题,如何实现检测数据变化
- 使用
onValuesChange
方法 或 使用Form.useWatch方法 - 还有一个笨方法是,React设置一个setStatus实时变量 和 form对应图片字段进行数值更新,使用实时变量进行页面的渲染
有不对的地方请大佬们指正 ^^