缘起
上传和下载是两个经典场景,做项目的时候遇到了这两种情况。
上传
设置上传按钮
const upoadImgCom = () => {
return (
<>
<label className={styles["upload-button"]} htmlFor="fileInputCompanyLogo">
+
</label>
<input
id="fileInputCompanyLogo"
accept={acceptFileTypeList}
onChange={uploadFileAction}
type="file"
multiple
/>
</>
);
};
相应样式文件
.upload-button {
color: #c3c3c3;
background: #f2f2f2;
width: 100px;
display: flex;
height: 40px;
justify-content: center;
align-items: center;
cursor: pointer;
&:hover {
color: #008cff;
border: 1px solid #008cff;
}
}
input {
display: none;
}
获取上传文件
注意这里获取到的uploadFile.files
是文件流类型,不能用数组方法。[...uploadFileEle.files]
转化为数组类型后,判断是否通过上传校验(大小、文件类型等)
const uploadFileAction = (e) => {
const uploadFileEle = document.querySelector("#fileInputCompanyLogo");
if (!uploadFileEle.files.length) return;
// 校验上传文件是否符合准入条件
const files = [...uploadFileEle.files];
const isValid = beforeUpload(files, fileSizeLimit, legTypeList);
if (!isValid) return;
const file = uploadFileEle.files[0];
dispatch({ type: "uploadImg", payload: file });
// onchange监听的为input的value值,只有再内容发生改变的时候去触发
// 成功后将value值置空,使得能够检测到下一次上传内容
e.target.value = "";
// }
};
关于beforeUpload
方法
以上传 20MB,类型为图片文件为例
// 文件大小限制
const fileSizeLimit = 20 * 1024 * 1024;
// 文件类型限制
const legTypeList = ["png", "jpg", "jpeg"];
// 1 KB = 1024 B
// 转换文件大小为可读单位
export const getFileSize = (fileSize) => {
let result = "";
if (fileSize >= 1073741824) {
// B => GB
result =
fileSize % 1073741824 === 0
? `${fileSize / 1073741824}G`
: `${Math.trunc(fileSize / 1073741824)}G`;
} else if (fileSize >= 1048576) {
// B => MB
result =
fileSize % 1048576 === 0
? `${fileSize / 1048576}MB`
: `${Math.trunc(fileSize / 1048576)}MB`;
} else if (fileSize >= 1024) {
// B => KB
result =
fileSize % 1024 === 0
? `${fileSize / 1024}KB`
: `${Math.trunc(fileSize / 1024)}KB`;
} else if (fileSize !== undefined) {
result = `${fileSize}B`;
}
return result;
};
// 根据文件名后缀获取当前文件类型
export const getLastFileTypeByName = (value) => {
const dotArray = value.split(".");
const lastDotArray = dotArray[dotArray.length - 1];
return lastDotArray;
};
export const getFileTypeBySource = (file, legitTypeList) => {
// 注意这里的类型判断一定要从文件名读取! ios 无 file.type!!!
const exactFileValue = file.name;
const lastFileTypeByName = getLastFileTypeByName(exactFileValue);
// 实测移动端 不走相册 直接选图片文件 尾缀为大写PNG 这里多加一层逻辑
// ↑ 从H5抄过来的 问题不大
// 这里全部转换成小写 进入匹配
let isLegitType = false;
isLegitType = legitTypeList.some((key) =>
lastFileTypeByName.toLowerCase().includes(key)
);
return isLegitType;
};
// 上传文件前置校验 文件类型 文件大小
export const beforeUpload = (files, fileSizeLimit, legTypeList) => {
const readableMaxFileSize = getFileSize(fileSizeLimit);
const fileSupportTypeText = legTypeList.join("、");
// if (!(files && files.length)) {
// message.error(`请添加${kind}`);
// return false;
// }
let flag = true;
// eslint-disable-next-line consistent-return
files.forEach((file) => {
const isLegFileType = getFileTypeBySource(file, legTypeList);
if (!isLegFileType) {
message.error(`文件支持格式: ${fileSupportTypeText}`);
flag = false;
}
if (file.size > fileSizeLimit) {
message.error(`文件最大支持${readableMaxFileSize}`);
flag = false;
}
});
return flag;
};
上传图片后可临时预览
https://juejin.cn/post/7240486780578480189
FileReader 转换为 base64 格式
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>图片本地预览示例</title>
</head>
<body>
<h3>阿宝哥:图片本地预览示例</h3>
<input type="file" accept="image/*" onchange="loadFile(event)" />
<img id="previewContainer" />
<script>
const loadFile = function (event) {
const reader = new FileReader();
reader.onload = function () {
const output = document.querySelector("#previewContainer");
output.src = reader.result;
};
reader.readAsDataURL(event.target.files[0]);
};
</script>
</body>
</html>
下载
图片、pdf、xml 的链接点击是预览
需要转换成 blob 文件流
五种方法 以及 对比
https://juejin.cn/post/6844904069958467592?searchId=20231215174642867C7A34315E52A747FB#heading-20
浏览器打开图片链接是直接预览还是下载
取决于图片链接的响应头 Content-Disposition 的属性
Content-Disposition 为 inline 在浏览器打开直接预览
Content-Disposition 为 attachment 在浏览器打开直接下载
链接:https://juejin.cn/post/7177346491059535932
值得一看的参考文章
前端二进制相关知识
https://juejin.cn/post/7262754051271032891?searchId=2023121416035302BFFAA3DF21DC00CAF9