实现拖拽上传,要求可以拖拽单文件、夹文件,多文件,及同时拖拽文件和文件夹,如果拖拽了文件夹要遍历文件下所有文件及子文件夹的文件
注意事项
调试需要使用HTTP
协议打开文件,如果使用本地协议调试将无法获取到拖拽的内容
假设页面中存在一个ID为dropBox
的div,给这个div添加拖拽事件,
其中dragover
和drop
事件是必须的,需要在dragover
中取消浏览器默认事件才能实现文件拖拽
let dropBox = document.getElementById("dropBox")
//监听文件拖拽移入(必须)
dropBox.addEventListener('dragover', FileDragHover, false)
//监听文件拖拽移出
dropBox.addEventListener('dragleave', FileDragLeave, false)
//监听文件拖拽放下(必须)
dropBox.addEventListener('drop', Drop, false)
//处理文件拖入事件
function FileDragHover(e) {
e.stopPropagation();
e.preventDefault();
//添加类名修改样式
e.target.classList.add("dropBoxHover")
e.target.innerText = "松开鼠标上传"
}
//处理拖拽离开事件
function FileDragLeave(e) {
e.stopPropagation();
e.preventDefault();
//移除类名修改样式
e.target.classList.remove("dropBoxHover")
e.target.innerText = "拖拽文件上传"
}
//处理文件拖拽放下事件
async function Drop(e) {
//阻止事件冒泡
e.stopPropagation();
//阻止事件的默认行为
e.preventDefault();
//储存获取到的文件列表
let fileList = [];
let DirectoryEntryList = [];
//清除样式
e.target.classList.remove("dropBoxHover")
if (e.dataTransfer.items) {
// 拖拽对象列表转换成数组
let items = new Array(...e.dataTransfer.items);
// 获得DirectoryEntry对象列表
for (let index = 0; index < items.length; index++) {
let e = items[index];
let item = null;
//兼容不同内核的浏览器
if (e.webkitGetAsEntry) {
item = e.webkitGetAsEntry();
} else if (e.getAsEntry) {
item = e.getAsEntry();
} else {
this.$alert("浏览器不支持拖拽上传", "提示");
return;
}
DirectoryEntryList.push(item);
}
if (DirectoryEntryList.length > 0) {
for (let index = 0; index < DirectoryEntryList.length; index++) {
let item = DirectoryEntryList[index];
if (item) {
//获取文件夹目录
let FileTree = await getFileTree(item);
// 拿到目录下的所有文件
if (Array.isArray(FileTree)) {
//展平文件夹
flattenArray(FileTree, fileList);
} else {
//方便后续处理,单文件时也包装成数组
fileList.push(FileTree);
}
}
}
}
}
console.log(fileList);
}
由于获取文件对象、获取目录文件等方法是异步的,结果要用回到函数的方式获取,非常不利于文件夹的递归操作,因此这里把异步的方法做了promise封装,调用方法返回一个promise对象,以便使用await 以同步的方式获得结果,以便于递归操作
/**
* 获取文件
*/
function fileSync(item) {
return new Promise((resolve, reject) => {
item.file(res => {
resolve(res);
});
});
}
//读取文件夹下的文件
function readEntriesSync(dirReader) {
return new Promise((rel, rej) => {
dirReader.readEntries(res => {
rel(res);
});
});
}
/**
* 获取文件目录结构树
*
*/
async function getFileTree(item) {
let that = this;
var path = item.fullPath || "";
let dir = new Array();
if (item.isFile) {
let resFile = await this.fileSync(item);
resFile.path = path;
return resFile;
// item为文件夹时
} else if (item.isDirectory) {
var dirReader = item.createReader();
let entries = await that.readEntriesSync(dirReader);
for (let i = 0; i < entries.length; i++) {
let proItem = await that.getFileTree(entries[i]);
dir.push(proItem);
}
return dir;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.dropBox {
width: 50%;
height: 200px;
margin: 150px auto;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
border: dashed 2px rgb(212, 212, 212);
color: rgb(148, 148, 148);
}
.dropBoxHover {
border-color: rgb(0, 195, 255);
box-shadow: 0 0px 8px rgba(0, 0, 0, 0.1) inset,
0 0px 3px rgba(0, 0, 0, .5) inset,
0 0px 5px rgba(0, 0, 0, .3) inset;
/* color: rgb(0, 195, 255); */
}
</style>
</head>
<body>
<p>用http协议打开,效果请看控制台</p>
<div class="dropBox" id="dropBox">
拖拽文件上传
</div>
</body>
<script>
let dropBox = document.getElementById("dropBox")
//监听文件拖拽移入
dropBox.addEventListener('dragover', FileDragHover, false)
//监听文件拖拽移出
dropBox.addEventListener('dragleave', FileDragLeave, false)
//监听文件拖拽放下
dropBox.addEventListener('drop', Drop, false)
function FileDragHover(e) {
e.stopPropagation();
e.preventDefault();
e.target.classList.add("dropBoxHover")
e.target.innerText = "松开鼠标上传"
}
function FileDragLeave(e) {
e.stopPropagation();
e.preventDefault();
e.target.classList.remove("dropBoxHover")
e.target.innerText = "拖拽文件上传"
}
async function Drop(e) {
//阻止事件冒泡
e.stopPropagation();
//阻止事件的默认行为
e.preventDefault();
//储存获取到的文件列表
let fileList = [];
let DirectoryEntryList = [];
//清除样式
e.target.classList.remove("dropBoxHover")
if (e.dataTransfer.items) {
// 拖拽对象列表转换成数组
let items = new Array(...e.dataTransfer.items);
// 获得DirectoryEntry对象列表
for (let index = 0; index < items.length; index++) {
let e = items[index];
let item = null;
//兼容不同内核的浏览器
if (e.webkitGetAsEntry) {
item = e.webkitGetAsEntry();
} else if (e.getAsEntry) {
item = e.getAsEntry();
} else {
this.$alert("浏览器不支持拖拽上传", "提示");
return;
}
DirectoryEntryList.push(item);
}
if (DirectoryEntryList.length > 0) {
for (let index = 0; index < DirectoryEntryList.length; index++) {
let item = DirectoryEntryList[index];
if (item) {
//获取文件夹目录
let FileTree = await getFileTree(item);
// 拿到目录下的所有文件
if (Array.isArray(FileTree)) {
//展平文件夹
flattenArray(FileTree, fileList);
} else {
//方便后续处理,单文件时也包装成数组
fileList.push(FileTree);
}
}
}
}
}
console.log(fileList);
}
/**
* 获取文件
*/
function fileSync(item) {
return new Promise((resolve, reject) => {
item.file(res => {
resolve(res);
});
});
}
//读取文件夹下的文件
function readEntriesSync(dirReader) {
return new Promise((rel, rej) => {
dirReader.readEntries(res => {
rel(res);
});
});
}
/**
* 展平数组
* @param {Array} 需要展平的数组
* @param {Array} 展平后的数组
*
*/
function flattenArray(array, result) {
// console.log(array, flatArray);
for (let i = 0; i < array.length; i++) {
if (Array.isArray(array[i])) {
this.flattenArray(array[i], result);
} else {
result.push(array[i]);
}
}
}
/**
* 获取文件目录结构树
*
*/
async function getFileTree(item) {
let that = this;
var path = item.fullPath || "";
let dir = new Array();
if (item.isFile) {
let resFile = await this.fileSync(item);
resFile.path = path;
return resFile;
// item为文件夹时
} else if (item.isDirectory) {
var dirReader = item.createReader();
let entries = await that.readEntriesSync(dirReader);
for (let i = 0; i < entries.length; i++) {
let proItem = await that.getFileTree(entries[i]);
dir.push(proItem);
}
return dir;
}
}
</script>
</html>