前言

现在开发基本上都是前后端分离,各自开发,互不影响,最后再前后端一起联调。在开发过程中,都会涉及数据上传。今天主要聊聊文件上传,包括自定义上传样式、如何选择文件夹、将后端返回的文件数据,根据文件路劲还原构造成树的形式渲染等。
接下来要实现的整体效果(注:这里没有后端,数据是前端根据上传的文件数据构造的):

前端实现文件夹上传,并回显文件树形结构

一、自定义上传样式

作为一个前端开发都知道,浏览器是无法直接访问本地文件夹的,所以如果用户想要在浏览器端选择本地文件夹上传,就需要通过使用HTML给的标签,将 type 设置成 “file”,这样就可以为用户提供在浏览器选择本地文件夹的能力。(当然,如果是在node环境下,是可以直接访问本地文件的,但是我们现在主要是讲在浏览器端)。
但是如果直接使用 ,我们知道它是有默认样式的,而且默认样式不太好看,如下图:在这里插入图片描述
这时候,我们一般都会自定义样式,根据设计师给的ui设计图,通过自定义样式,实现一些比较好看的上传样式,下图是写的两个基本样式,如下图。在这里插入图片描述
实现原理很简单,先将标签通过 display: none 隐藏起来,这样用户在浏览器端就看不见默认样式,然后再根据具体需求自定义样式,设置点击事件,当点击自定义样式这个节点时,获取到 节点并触发其click事件即可。如下图。
在这里插入图片描述

二、上传文件夹

通常情况下,我们都是上传某一个文件或者某一类型问价,很少有上传整个文件夹的,但是实际开发中,肯定是会有这样的需求的。那如果遇到这样的需求总不能将文件夹里的内容一个一个选择上传吧,那样太慢了。其实是有一个属性可以选择整个文件夹的。只需要加上 webkitdirectory、 directory 像这样<input ref=“upload” type=“file” webkitdirectory directory style=“display: none;” @change=“changeUpload” /> 就可以实现上传整个文件夹。以下是没有加webkitdirectory、 directory这个属性之前的选择状态和加了之后的选择状态
没加之前
在这里插入图片描述
加了之后
在这里插入图片描述
这样就可以上传整个文件夹啦。关于input标签的其他属性,大家感兴趣的,也可以去网站查阅。https://developer.mozilla.org/docs/Web/HTML/Element/input

三、前端怎么将后端返回的文件数据,根据路径处理成树形结构展示。

如何你们的后端很好的话,他们会直接将数据处理成树形结构的数据返回回来,这时候你就只需要渲染出来就行了。但是如果你们的后端返回的是一个纯一维数组,那么就需要前端做一些处理。
例如后端返回的数据结构是这样的


const files = [
  { path: 'project50/struct.json', fileType: 'json', fileName: 'struct', fileSize: 264, fileKey: 'dsa784564f45dfdsfsfsafa45' },
  { path: 'project50/__project', fileType: 'json', fileName: 'struct', fileSize: 264, fileKey: 'dsa784564f45dfdsfsfsafa45' },
  { path: 'project50/config/config/config.json', fileType: 'json', fileName: 'struct', fileSize: 264, fileKey: 'dsa784564f45dfdsfsfsafa45' },
  { path: 'project50/config/custom.flw', fileType: 'json', fileName: 'struct', fileSize: 264, fileKey: 'dsa784564f45dfdsfsfsafa45' },
  { path: 'project50/config/README.md', fileType: 'json', fileName: 'struct', fileSize: 264, fileKey: 'dsa784564f45dfdsfsfsafa45' },
  { path: 'project50/kaman/README.md', fileType: 'json', fileName: 'struct', fileSize: 264, fileKey: 'dsa784564f45dfdsfsfsafa45' },
  { path: 'project50/kaman/url/struct.json', fileType: 'json', fileName: 'struct', fileSize: 264, fileKey: 'dsa784564f45dfdsfsfsafa45' },
  { path: 'project50/kaman/url/jks.json', fileType: 'json', fileName: 'struct', fileSize: 264, fileKey: 'dsa784564f45dfdsfsfsafa45' },
  { path: 'project50/kaman/url/test/word.txt', fileType: 'json', fileName: 'struct', fileSize: 264, fileKey: 'dsa784564f45dfdsfsfsafa45' },
  { path: 'project50/kaoshi/abc/cao.exls', fileType: 'json', fileName: 'struct', fileSize: 264, fileKey: 'dsa784564f45dfdsfsfsafa45' }
];

那么你就需要根据数据中的 path 字段,将文件夹还原出来。如下图所示。在这里插入图片描述
其实要实现也不难,这里主要是要考虑到一种情况,那就是如何处理同名的子文件路径。接下来就直接上代码了。


const buildFileStructure = (files: any[]) => {
  const flag = files.every(file => {
    return file.path;
  })
  // 没有路径信息就返回后端数据,否则会有报错
  if (!flag) {
    return files;
  }
  const root: any[] = [];
  const map: any = {};
  files.forEach(file => {
    // 分割路径
    const paths = file.path.split('/');
    let currentLevel = root;
    paths.forEach((path: string, index: number) => {
      const existPath = paths.slice(0, index + 1).join('/');
      if (!map[existPath]) {
        const newLevel = {
          fileName: path,
          key: existPath,
          children: [],
        };
        if (index === paths.length - 1) {
          Object.assign(newLevel, file);
        };
        map[existPath] = newLevel;
        currentLevel.push(newLevel);
      }
      currentLevel = map[existPath].children;
    });
  });
  filertChildren(root);
  dataSource.value.push(root[0]);
  return root;
}

const filertChildren = (list: any[]) => {
  list.forEach(child => {
    if (child.children && child.children.length > 0) {
      filertChildren(child.children);
    } else {
      delete child.children;
    }
  })
}

总结

因为之前的项目中,有涉及到这样的需求,所以在闲暇之余,也是无事做,便想到将其记录下来,如果有遇见一样的需求,可以参考一下。以上就是关于前端自定义上传样式、上传文件夹、将后端返回的文件数据,根据路径还原构建成树形数组渲染出来,还原文件夹的结构的整个过程,没有复杂的代码和逻辑。开发嘛,完成比完美更重要。不管黑猫白猫,能抓住耗子就是好猫。所以不管什么办法,只要能实现就行,关于优化,那都是后期的事情了(当然,能有最好的解决方案,那肯定是极好的)。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐