相信你一定经常遇见过下面的场景?
?嘿嘿,给好兄弟分享点快乐资源
?为什么阻止我分享快乐,每次都得打包才发送,麻烦死了。
不行我要自己弄一个,让大家都能快乐分享。
我的思路
既然要用文件夹分享给对方,我们就得简单了解下文件夹是什么。
文件夹是一种用于组织和存储文件的容器,它本身不是一种文件,但在计算机系统中被视为一种特殊类型的文件
也就是说我们实际上是不能直接传递文件夹的,因为文件夹只是为了方便我们查看文件的路径而存在的,并不是真实的文件。
动手实践?
方式一:直接发送多个文件
思路:
- 拖动文件夹到浏览器
- 浏览器获取文件夹里的每个文件
- 将获取到的文件发送请求给对方
1:让我们的上传区域可放置
首先我们给拖动区域添加两个响应事件dragover
和drop
,这样这个区域就能获取到拖动文件。(如果不熟悉可以到我写的另一篇文章中熟悉一下拖拽事件)
<div class="dropzone">
将文件拖到这里
</div>
const dropzone = document.querySelector('.dropzone');
dropzone.addEventListener('dragover', (event) => {
event.preventDefault(); //阻止默认行为,允许放置
});
dropzone.addEventListener('drop', (event) => {
event.preventDefault(); //阻止浏览器默认行为,不会自动打开文件管理页面
const DataTransferItemList = event.dataTransfer.items; // 获取文件的数据
console.log(DataTransferItemList); // 打印看看
});
2:获取文件夹里的数据
这时候就要有请我们的老朋友DataTransfer拖动对象了,看看它能为我们提供什么数据:
DataTransfer.files
:包含数据传输中可用的所有本地文件的列表。如果拖动操作不涉及拖动文件,则此属性为空列表。
- ⭐️
DataTransfer.items
:提供一个包含所有拖动数据列表的DataTransferItemList
对象。
DataTransfer对象用于保存拖动并放下的数据,我们希望能得到文件夹的的所有文件,你可能会想要使用DataTransfer.files,不过很遗憾它只包含我们拖动时的文件,并不能获取到内部的文件
,所以我们选择使用DataTransfer.items来获取我们的文件。
3:?DataTransfer.items的处理
DataTransfer.items返回DataTransferItemList
对象是一组拖动列表,里面的每个拖动项DataTransferItem
就表示我们拖动的文件。
比如你拖动两个文件夹或两个文件到浏览器,那么列表就有两个DataTransferItem
对象。
所以我们的重点是处理DataTransferItem
对象。
具体流程:
1:使用DataTransferItem.webkitGetAsEntry()
方法(非标准),获取文件夹对应文件系统的实体对象。
dropzone.addEventListener('drop', (event) => {
event.preventDefault();
const dataTransferItemList = event.dataTransfer.items // 获取文件的数据
for(const dataTransferItem of dataTransferItemList) {
const file = dataTransferItem.webkitGetAsEntry();
console.log(file);
}
});
打印一下可以看到里面有一个属性isFile
,用来判断是文件夹还是文件类型,会作为我们的一个判断条件。
2:编写文件夹处理函数handlefile(file)
function handlefile(file) {
const dirReader = file.createReader()
dirReader.readEntries(function(entries) {
console.log(entries);
})
}
const dirReader = file.createReader()
: 这里创建了一个文件夹读取器 dirReader
,用于读取指定文件夹 file
中的内容。
dirReader.readEntries(function(entries) { ... })
: 这是异步方法,它读取文件夹中的所有文件和子文件夹,并在读取完成后执行回调函数。回调函数中的 entries
是一个包含文件夹中文件和子文件夹的数组。
经过不懈努力,我们终于得到想要的entries
?
因为文件夹中可能还有文件夹,所以我们需要对文件夹里的文件夹也进行递归处理。
让我们完善一下代码
function handlefile(file) {
if (file.isFile) {
// 是文件执行上传操作
//file.file() 方法用于读取文件内容
file.file(function(f) {
// f才是最终的文件
console.log(f);
const text = document.createTextNode(f.name+'—');
dropzone.appendChild(text);
return
})
} else {
// 是文件夹,读取文件夹里的文件,遍历文件夹
const dirReader = file.createReader()
dirReader.readEntries(function(entries) {
// 遍历entries,对文件进行处理
for (let i = 0; i < entries.length; i++) {
handlefile(entries[i])
}
})
}
}
最终效果:
我们获得最后的f
就是我们需要的文件,只需要将这个f
文件通过网络请求发送给对方就行了。
方式二:压缩上传(思路)
相信以你聪明的脑瓜,一定发现了这种方式的弊端,要是我们发送的文件夹有100个文件,那就要发起100个请求,这会增加网络通信的开销,可能会导致网络拥塞和传输延迟。
所以把文件夹打包成压缩包再发送是最高效的,当然考虑到我很懒,不想自己压缩打包,那就把这个活交给我们的浏览器干就好了。
可以看看使用JSZip等库来帮助我们,这里就提供思路了,具体操作小伙伴们自行探索。
完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.dropzone {
width: 300px;
height: 300px;
background-color: aquamarine;
}
</style>
</head>
<body>
<div class="dropzone">
将文件拖到这里:
</div>
<script>
const dropzone = document.querySelector('.dropzone');
function handlefile(file) {
if (file.isFile) {
// 是文件执行上传操作
//file.file() 方法用于读取文件内容
file.file(function(f) {
// f才是最终的文件
console.log(f);
const text = document.createTextNode(f.name+'—');
dropzone.appendChild(text);
return
})
} else {
// 是文件夹,读取文件夹里的文件,遍历文件夹
const dirReader = file.createReader()
dirReader.readEntries(function(entries) {
// 遍历entries,对文件进行处理
for (let i = 0; i < entries.length; i++) {
handlefile(entries[i])
}
})
}
}
dropzone.addEventListener('dragover', (event) => {
event.preventDefault(); //阻止默认行为,允许放置
});
dropzone.addEventListener('drop', (event) => {
event.preventDefault();
const dataTransferItemList = event.dataTransfer.items // 获取文件的数据
for(const dataTransferItem of dataTransferItemList) {
const file = dataTransferItem.webkitGetAsEntry();
handlefile(file);
}
});
</script>
</body>
</html>