修修upload吧
最近做的项目使用到upload,需要满足既可以上传图片又可以上传pdf且需要能预览。
最开始霹雳吧啦一顿操作,写完了,如下:
const beforeUpload = (typeI, file) => {
const { name, size } = file;
const myType = name.slice(name.indexOf('.') + 1);
const isJpgOrPng = ['jpg', 'jpeg', 'png', 'bmp', 'pdf'].includes(myType);
if (!isJpgOrPng) {
message.error('上传格式不符合要求');
}
const isLt10M = size / 1024 / 1024 < 10;
if (!isLt10M) {
message.error('文件大小需要在10M以内');
}
return isJpgOrPng && isLt10M;
}
思路就是上传时候能拿到文件名,做个判断就好了,轻轻松松。(typeI
是多处使用自个做的标识)
测试测完了,项目经理提了个问题,说我把docx
文件后缀改成pdf
,上传成功了,但是预览出现问题了;嘴上怼了回去,哪有这样搞的,这样弄的电脑都不会操作吧,基本操作都不了解;心里开始琢磨怎么解决了,网上一顿输出找到了一版我也看不懂的操作,又自己东拼西凑了一版,如下:
第一种方式:这是做读取判断文件是否是对应的格式
function readBuffer(file, start = 0, end = 2) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.onerror = reject;
reader.readAsArrayBuffer(file.slice(start, end));
});
}
function check(headers) {
return (buffers, options = { offset: 0 }) =>
headers.every(
(header, index) => header === buffers[options.offset + index]
);
}
function stringToBytes(string) {
return [...string].map((character) => character.charCodeAt(0));
}
async function handleChange(file) {
const isPNG = check(stringToBytes("%PDF")); // 决定进行哪种文件判断
const buffers = await readBuffer(file, 0, 8);
const uint8Array = new Uint8Array(buffers);
return await isPNG(uint8Array);
}```
第二种方式:原理就是通过FileReader读取文件,通过文件开头格式进行判断是否是对应的文件;
像修改文件类型,浏览器会将其对应的file.type也会随着更改,这种可以改为根据文件最后的后缀名进行判断。
但是碰上直接改文件后缀的不好使了啊。
```javascript
const getFileMimeType = (file) => {
const reader = new FileReader();
reader.readAsArrayBuffer(file);
return new Promise((resolve, reject) => {
reader.onload = (event) => {
try {
let buffer = [...Buffer.from(event.target.result)];
// 仅要文件的前四位就够了
buffer = buffer.splice(0, 4);
buffer.forEach((num, i, arr) => {
arr[i] = num.toString(16).padStart(2, '0'); // 转成16进制且当不足两位数时在前头补个0
});
// 504b0304 是 xlsx 的文件头 16进制
// 25504446 是 pdf 的文件头 16进制
resolve(buffer.join('') === '25504446');
} catch (e) {
// 读取文件头出错 默认不是合法文件类型
reject();
}
};
});
}
const beforeUpload = (typeI, file) => {
return new Promise(async (resolve, reject) => {
const { name, size } = file;
const myType = name.slice(name.indexOf('.') + 1);
const isJpgOrPng = ['jpg', 'jpeg', 'png', 'bmp', 'pdf'].includes(myType);
// const isPdf = await getFileMimeType(file);
const isPdf = await handleChange(file); // 调用上述方法符合的返回true,否则false
if (myType == 'pdf' && !isPdf) {
message.error('上传文件不是pdf格式文件');
reject();
}
if (!isJpgOrPng) {
message.error('上传格式不符合要求');
reject();
}
const isLt10M = size / 1024 / 1024 < 10;
if (!isLt10M) {
message.error('文件大小需要在10M以内');
reject();
}
resolve();
})
};
细心的小伙伴可能发现了,beforeUpload
方法换写法了,用上了promise
;因为getFileMimeType(file)
和handleChange(file)
是异步函数。有人的会问怎么不用async
和 await
了,实际大伙自个使用试试,原因我也不太清楚,会出现beforeUpload
限制条件都失效了,onchange
走了三遍;真的是很无奈啊,然后再看了下官网beforeUpload
的使用,可以返回一个promise
,那就改一下吧,成了。