实现拖拽上传文件夹
前言
我们在很多的项目场景当中,都会碰到需要上传文件的情况,相信大部分前端仔都对上传的机制熟稔于心了,无非就是表单上传,拖拽上传等等,基本都是玩的溜溜的了。而今天我们讲的是其中不为人知的一块内容---通过拖拽的方式来上传整个文件夹的内容~
我们通过
<input type='file' multiple>只能实现多文件的上传,但是对于文件夹的上传依旧是束手无策
一、拖拽事件对象
既然讲的是拖拽上传文件夹,那么我们自然从我们的拖拽的事件对象讲起了。
ev.dataTransfer对象
我们来看一下MDN对dataTransfer对象的描述:
DataTransfer被用于承载拖拽和拖放时的数据,它可以承载多个数据项。
注意:当我们的拖放动作解释并完成回调函数之后,dataTransfer中的数据项就会被清理回收,如果我们在拖拽的过程需要做一些额外的判断或者在回调外进行操作时,需要强引用这些数据项的内容,防止其被垃圾回收机制给回收掉。
DataTransfer.files:
这个属性就是一个文件伪数组,用来存储拖拽对象的文件属性,如果拖拽的不是文件,那么这个数组为空。
DataTransfer.items
该属性就是我们这次的关注重点,数据选项,为什么这么说,因为这个数据项支持文件的读取,而其特有的文件的属性以及最为重要的entry对象是我们实现文件夹上传的重中之重。
DataTransfer.getData/DataTransfer.setData
这个API是DataTransfer比较重要的一个属性,他可以自由的设置和读取属性。着就给我们进行组件的拖拽创造了无限的可能。一般我们都是通过源组件的dragstart事件调用DataTransfer.setData()传入数据,然后在目的组件当中通过DataTransfer.getData()来获取数据进行相关操作。
注意:这两个API无法直接传入对象,建议通过JSON序列化和反序列化的手段来进行对象的传递。
由于DataTransfer含有大量额外的接口以及属性我们就不展开讨论,有兴趣的童鞋可以去MDN自行阅读,说不定就能找到满足你业务需求的接口哦~
DataTransfer.items
DataTransfer.items是一个DataTransferItemList对象,这个对象同样的也是一个伪数组,它含有length属性。每一个数组成员都是一个DataTransferItem对象。我们的拖拽文件夹操作就是需要依靠这个对象来实现的。
二、DataTransferItem
我们接着着重来看这个对象。
DataTransferItem.webkitGetAsEntry()
这个API就是我们引出下一个关键对象的入口,这个是一个非标准的API看他的函数名我们也可以知道是支持webkit的一个API。这个API是干什么的?我们来看一下MDN官方的解释(本人翻译,建议可以看原版英文):
如果DataTransferItem承载的是一个文件数据,那么我们可以用调用该API来创建一个FileSystemFileEntry或者FileSystemDirectoryEntry对象。望文生义,很显然我们可以通过这两个对象来区分我们拖拽的是文件还是文件夹。这两个对象都是通过FileSystemEntry接口扩展的
这个两个对象同时都拥有isFile和isDirectory属性用来描述这个对象是文件还是文件夹。我们可以判断这两个属性从而进一步进行操作。
FileSystemEntry.fullPath这个属性是用来保存完全路径的,根目录就是最初拖拽的文件夹路径。我们后续上传服务器就会用到这个属性。
注意:接下来大部分的API都是非标准的API,在后续可能有变化,如果需要在公司业务使用,建议标注清楚使用事项和注意事项。
FileSystemFileEntry.file()/FileSystemDirectoryEntry.createReader()
FileSystemFileEntry.file()函数用来实际读取文件内容,该函数可以注册两个回调函数,一个成功回调,一个失败错误回调。在成功回调中,会把真正的file对象传入进来,然后后面做什么事,就不言而喻了吧~
FileSystemDirectoryEntry.createReader()
这个API用来实现创建一个FileSystemDirectoryReaderAPI用来读取文件夹中的FileSystemFileEntry对象了。和FileSystemFileEntry.file()用法一样,也是在FileSystemDirectoryReader.readEntries中注册成功回调,然后在回调中传入实际的entries数组。到了这里我们差不多也就了解了整个的相关API的情况了,那么接下来就是递归遍历文件夹的工作了,代码就不写了逻辑也不是特别难。到此结束