需求是使用 VUE3 实现上传文件夹,其功能主要依赖于 <input>
标签的属性 webkitdirectory
:
<input
ref="uploadFolderRef"
type="file"
style="display: none"
@change="submitUpload"
webkitdirectory
multiple
/>
<el-button @click="openUploadDialog">上传文件夹</el-button>
将 input 标签的 display 属性设为 none 使其隐藏起来,后续通过点击按钮触发上传框的点击事件:
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
const uploadFolderRef = ref()
const openUploadDialog = () => {
uploadFolderRef.value.click()
}
const submitUpload = (e: any) => {
const files = Array.from(e.target.files)
Promise.all(
files.map((file: any) => {
const form = new FormData()
form.append('file', file)
return UploadApi.upload(form)
}),
)
.then(() => {
ElMessage.success('上传成功')
})
.catch(() => {
ElMessage.error('上传失败')
})
}
存在问题:重复上传相同文件夹,只有第一次有效,后续选择文件夹无法完成上传。
原因是上传框的提交上传是 onchange
事件,选择相同的文件夹的 value
属性值是一样的,因此无法触发;
解决方案:
-
手动修改上传框的
value
属性为空;const uploadFolderRef = ref() /* 打开上传框之前,先将上传框的value属性设为空 */ const openUploadDialog = () => { uploadFolderRef.value.value = '' uploadFolderRef.value.click() }
-
采用 JavaScript 生成上传框,这样将每次都生成新的上传框;
<template> <el-button @click="createFileInput">上传文件夹</el-button> </template> <script setup lang="ts"> const createFileInput = () => { const input = document.createElement('input') input.style.display = 'none' input.type = 'file' input.multiple = true input.webkitdirectory = true input.onchange = submitUpload document.body.appendChild(input) input.click() } </script>