Vue批量上传文件和文件夹

2,437 阅读1分钟

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)]);
};