最近项目中有上传图片文件的需求:

点击选择图片的按钮

mui的实现是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<input
accept="image/*"
id="contained-button-file"
style={{ display: 'none' }}
// 选多张图片
multiple
type="file"
onChange={(e) => {
// 下面讲
clickToUploadFile(e.target.files)
}}
/>
<label
htmlFor="contained-button-file"
>
<Button
variant="contained"
// 必须加这一行
component="span"
>
导入图片
</Button>
</label>

formData

后端要求使用formData,于是快速上手了formData,主要用到.append方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// fileList => input onChange callback => e.target.files
// 是一个对象,{1: file1, 2: file2, length: 2, ...}
function clickToUploadFile(fileList) {
const reqData = new FormData()

// 项目id
reqData.append('projectID', id)
// 上传图片数量
reqData.append('imgNum', `${fileList.length}`)

for (const key in fileList) {
// 图片
reqData.append(`img${parseInt(key) + 1}`, fileList[key])
// uuid(下边讲)
const uuid = generateUUID(fileList[key])
reqData.append(`uuid${parseInt(key) + 1}`, `${uuid}`)
// 图片名
reqData.append(`name${parseInt(key) + 1}`, fileList[key].name)

// 只取file,不要length以及之后的属性
if (parseInt(key) === fileList.length - 1) {
break
}
}

formData的实例对象不能直接通过console.log查看,需要这样做:

1
2
3
4
// FormData.entries:返回一个包含所有键值对的interator对象
for (const pair of reqData.entries()) {
console.log(pair[0] + ', ' + pair[1])
}

uuid的生成

UUID (Universally unique identifier),通用唯一识别码。

前端需要为每个图片生成独一无二的uuid,并放在formData中传给后端,就像刚才做的那样。

我直接采用图片时间戳 * 图片大小 / 大质数的方式,保证在低并发情况下,每个图片都拥有独一无二的uuid。

参考

MDN-formData