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

相关推荐
烬头88212 分钟前
React Native鸿蒙跨平台采用了函数式组件的形式,通过 props 接收分类数据,使用 TouchableOpacity实现了点击交互效果
javascript·react native·react.js·ecmascript·交互·harmonyos
Amumu121382 分钟前
Vuex介绍
前端·javascript·vue.js
We་ct3 分钟前
LeetCode 54. 螺旋矩阵:两种解法吃透顺时针遍历逻辑
前端·算法·leetcode·矩阵·typescript
2601_9498095914 分钟前
flutter_for_openharmony家庭相册app实战+相册详情实现
javascript·flutter·ajax
qq_1777673719 分钟前
React Native鸿蒙跨平台通过Animated.Value.interpolate实现滚动距离到动画属性的映射
javascript·react native·react.js·harmonyos
2601_9498333928 分钟前
flutter_for_openharmony口腔护理app实战+饮食记录实现
android·javascript·flutter
2601_9494800636 分钟前
【无标题】
开发语言·前端·javascript
css趣多多41 分钟前
Vue过滤器
前端·javascript·vue.js
理人综艺好会1 小时前
Web学习之用户认证
前端·学习
●VON1 小时前
React Native for OpenHarmony:项目目录结构与跨平台构建流程详解
javascript·学习·react native·react.js·架构·跨平台·von