1. 批量上传文件
文件的批量上传比较简单,在input标签中加上multiple属性后即可一次性选择多个文件
<input type="file" @change="onSelectFiles" multiple />
然后通过监听input标签的change事件获取并上传这些文件。
const onSelectFiles = ({ target }) => {
const files = [].map.call(target.files, (file) => ({ type: "file", name: file.name, parentPath: "/", file }));
onUploadFiles(files);
}
const onUploadFiles = async (files) => {
if (!files?.length) return;
const fd = new FormData();
files.forEach((file) => {
fd.append("file", file, file.name);
fd.append("parentPath", file.parentPath);
});
await fetch("后端API地址", { method: "post", body: fd, headers: { "Content-Type": "multipart/form-data" } });
}
2. 上传文件夹
文件夹的上传会稍微难一点,还是使用input标签,并加上webkitdirectory属性,这样就可以选择文件夹了。
<input type="file" @change="onSelectFolder" webkitdirectory />
不论文件夹的层级有多深,change事件中的target.files都是一维数组,也就是说文件夹中的所有层级都会被拍平,若想恢复层级关系,则需要通过每个文件的webkitRelativePath(相对路径)属性来重新组合。
const onSelectFolder = ({ target }) => {
//假如上传一个A文件夹里有一个B文件夹,B文件夹里有一个C.text文件,那么该文件的webkitRelativePath值就为A/B/C.text
let folder = { type: "folder", name: target.files[0].webkitRelativePath.split("/")[0], parentPath: "/", childs: new Map() };
[].forEach.call(target.files, (file) => {
const folders = file.webkitRelativePath.split("/").slice(1, -1); //文件的上级文件夹列表
let parent = folder;
folders.forEach((F) => {
parent.childs.has(F) || parent.childs.set(F, { type: "folder", name: F, parentPath: parent.parentPath + "/" + parent.name, childs: new Map() }); //创建父级文件夹
parent = parent.childs.get(F);
});
parent.childs.set(file.name, { type: "file", name: file.name, parentPath: parent.parentPath + "/" + parent.name, file }); //存放文件
});
onUploadFolder(folder);
};
const onUploadFolder = async ({ name, parentPath, childs }) => {
await fetch("创建文件夹的接口", { method: "post", body: { name, parentPath } });
const folders = [...childs.values()].filter(({ type }) => type == "folder");
const files = [...childs.values()].filter(({ type }) => type == "file");
await Promise.all([...folders.map((F) => onUploadFolder(F)), onUploadFiles(files)]);
};