原理
注意:有浏览器版本限制
实现文件夹上传有两种:一种是通过将文件夹拖拽到浏览器,实现上传;另一种是通过 <input>
标签,用户选择文件夹实现上传
使用 vue
开发时,需要添加 @dragover="e=>e.preventDefault()"
。否则拖拽文件夹不会触发 @drop
,只会触发浏览器默认行为
示例代码
<template>
<div id="app">
<div id="p"></div>
<img alt="Vue logo" src="./assets/logo.png">
<div>
<label for="folder">
Choose folder or files to upload:
<input id="folder" type="file" webkitdirectory mozdirectory @change="handleInputChanged">
</label>
</div>
<div id="drop" @dragover="e=>e.preventDefault()"
@drop="handleDropEvent">
Drop folder for files to upload
</div>
</div>
</template>
<script>
const traverseFileTree = function self(item, p) {
const path = p || '';
if (item.isFile) {
// Get file
item.file((file) => {
console.log('file:', file, path);
const form = new FormData();
form.append('file', file);
form.append('dir', path);
form.append('name', file.name);
// TODO: upload file
});
} else if (item.isDirectory) {
// Get folder contents
const dirReader = item.createReader();
dirReader.readEntries((entries) => {
for (let i = 0; i < entries.length; i += 1) {
self(entries[i], `${path}${item.name}/`);
}
});
}
};
export default {
name: 'App',
methods: {
handleInputChanged(evt) {
if (!evt || !evt.target) return;
const { files: fileList } = evt.target;
console.log('this:', this);
for (let i = 0; i < fileList.length; i += 1) {
const file = fileList[i];
const form = new FormData();
form.append('file', file);
form.append('path', file.webkitRelativePath);
form.append('name', file.name);
// TODO: upload file
}
},
handleDropEvent(evt) {
evt.stopPropagation();
evt.preventDefault();
const { length } = evt.dataTransfer.items;
for (let i = 0; i < length; i += 1) {
// recursive directory search
traverseFileTree(evt.dataTransfer.items[i].webkitGetAsEntry());
}
return false;
},
},
};
</script>
<style lang="less">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
#drop {
height: 200px;
line-height: 200px;
margin-top: 20px;
background-color: aqua;
}
</style>