vue文件或文件夹拖拽上传

一、示例

二、组件代码

javascript 复制代码
<template>
  <div
    class="drop-area"
    :class="{ dragging: isDragging }"
    @dragover.prevent="handleDragOver"
    @dragleave="handleDragLeave"
    @drop.prevent="handleDrop"
  >
    <el-icon class="el-icon--upload"><upload-filled /></el-icon>
    <p>拖拽文件或文件夹到此处,开始上传</p>
    <!-- <p v-if="fileList.length">已选择 {{ fileList.length }} 个文件</p> -->
  </div>
</template>

<script setup>
  import { ref, defineEmits } from 'vue'

  const emits = defineEmits(['change'])

  // 响应式状态
  const isDragging = ref(false)
  const fileList = ref([])

  // 处理拖拽进入
  const handleDragOver = (e) => {
    isDragging.value = true
    e.dataTransfer.dropEffect = 'copy'
  }

  // 处理拖拽离开
  const handleDragLeave = () => {
    isDragging.value = false
  }

  // 处理文件放置
  const handleDrop = async (e) => {
    isDragging.value = false
    const droppedFiles = await extractFilesFromDropEvent(e)
    fileList.value = [...droppedFiles]
    console.log(droppedFiles, 123)
    emits('change', droppedFiles)
  }

  // 从拖拽事件中提取所有文件
  const extractFilesFromDropEvent = async (event) => {
    const items = event.dataTransfer.items
    console.log('拖拽项数量:', items?.length)
    if (!items) return []

    // 使用Promise.all并行处理所有文件项
    const promises = Array.from(items).map(async (item) => {
      if (item.kind === 'file') {
        const entry = item.webkitGetAsEntry()
        if (entry) {
          console.log('正在处理文件:', entry)
          // 递归处理文件条目
          const fileResult = await traverseFileEntry(entry, '')
          return fileResult
        }
      }
      return null
    })

    // 等待所有处理完成并合并结果
    const results = await Promise.all(promises)
    // 扁平化结果数组并过滤掉null值
    return results.flat().filter(Boolean)
  }

  // 递归遍历文件系统条目
  const traverseFileEntry = (entry, relativePath) => {
    return new Promise((resolve) => {
      if (entry.isFile) {
        // 处理文件
        entry.file((file) => {
          // 添加相对路径信息
          file.relativePath = relativePath ? `${relativePath}/${file.name}` : ''
          resolve(file)
        })
      } else if (entry.isDirectory) {
        // 处理目录
        const dirReader = entry.createReader()
        dirReader.readEntries(async (entries) => {
          const subPath = relativePath
            ? `${relativePath}/${entry.name}`
            : entry.name

          // 对目录项使用Promise.all并行处理
          const promises = Array.from(entries).map((subEntry) =>
            traverseFileEntry(subEntry, subPath)
          )

          const results = await Promise.all(promises)
          // 扁平化目录下的所有文件
          resolve(results.flat().filter(Boolean))
        })
      } else {
        resolve(null)
      }
    })
  }
</script>

<style scoped>
  .drop-area {
    width: 100%;
    min-height: 100px;
    border: 2px dashed #ccc;
    border-radius: 8px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 20px;
    transition: all 0.3s ease;
    margin: 0px;
  }

  .drop-area.dragging {
    border-color: #409eff;
    background-color: rgba(64, 158, 255, 0.1);
  }

  .drop-area p {
    margin: 5px 0;
    color: #666;
  }
  .drop-area .el-icon--upload {
    font-size: 50px;
    color: #999;
  }
</style>

@change获取上传file文件

相关推荐
徐小夕@趣谈前端6 分钟前
如何实现多人协同文档编辑器
javascript·vue.js·设计模式·前端框架·开源·编辑器·github
YCOSA202543 分钟前
ISO 雨晨 26200.6588 Windows 11 企业版 LTSC 25H2 自用 edge 140.0.3485.81
前端·windows·edge
小白呀白1 小时前
【uni-app】树形结构数据选择框
前端·javascript·uni-app
吃饺子不吃馅1 小时前
深感一事无成,还是踏踏实实做点东西吧
前端·svg·图形学
90后的晨仔2 小时前
Mac 上配置多个 Gitee 账号的完整教程
前端·后端
少年阿闯~~2 小时前
CSS——实现盒子在页面居中
前端·css·html
开发者小天2 小时前
uniapp中封装底部跳转方法
前端·javascript·uni-app
阿波罗尼亚2 小时前
复杂查询:直接查询/子查询/视图/CTE
java·前端·数据库
武昌库里写JAVA3 小时前
SpringCloud与微服务
vue.js·spring boot·sql·layui·课程设计
正义的大古3 小时前
OpenLayers地图交互 -- 章节九:拖拽框交互详解
前端·vue.js·openlayers