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文件

相关推荐
WooaiJava29 分钟前
AI 智能助手项目面试技术要点总结(前端部分)
javascript·大模型·html5
LYFlied33 分钟前
从 Vue 到 React,再到 React Native:资深前端开发者的平滑过渡指南
vue.js·react native·react.js
爱喝白开水a1 小时前
前端AI自动化测试:brower-use调研让大模型帮你做网页交互与测试
前端·人工智能·大模型·prompt·交互·agent·rag
Never_Satisfied1 小时前
在JavaScript / HTML中,关于querySelectorAll方法
开发语言·javascript·html
董世昌411 小时前
深度解析ES6 Set与Map:相同点、核心差异及实战选型
前端·javascript·es6
B站_计算机毕业设计之家1 小时前
豆瓣电影数据采集分析推荐系统 | Python Vue Flask框架 LSTM Echarts多技术融合开发 毕业设计源码 计算机
vue.js·python·机器学习·flask·echarts·lstm·推荐算法
WeiXiao_Hyy2 小时前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
吃杠碰小鸡2 小时前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone2 小时前
C#使用Aspose.Words把 word转成图片
前端·c#·word
xjt_09012 小时前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js