博客 / 詳情

返回

文件/文件夾拖拽上傳

流程

  1. 通過drop事件獲取用户拖拽的文件
  2. 如果是文件,執行上傳
  3. 如果是目錄,遞歸目錄下所有的文件,執行上傳

代碼

<template>
  <div
    @dragover.prevent
    @dragenter.prevent
    @dragleave.prevent
    @drop.prevent="handleDrop"
  >拖拽區域</div>
</template>

<script setup lang="ts">
const uploadFiles = () => {}

// TODO: 這裏的directory需要聲明一下類型
const traverseDirectory = async (directory) => {
  const fileList: File[] = []
  const reader = directory.createReader()

  const readEntriesSync = reader => new Promise<FileSystemFileEntry[]>((resolve, reject) => {
    reader.readEntries(resolve, reject)
  })

  const entries = await readEntriesSync(reader)
  for (const entry of entries) {
    if (entry.isFile) {
      const file: File = await new Promise((resolve, reject) => {
        entry.file(resolve, reject)
      })
      Object.defineProperty(file, 'webkitRelativePath', {
        value: entry.fullPath,
      })
      fileList.push(file)
      return
    }

    if (entry.isDirectory) {
      const subFiles = await traverseDirectory(entry)
      fileList.push(...subFiles)
      return
    }
  }
  return fileList
}

// TODO: 這裏的data需要聲明一下類型
const upload = async (data) => {
  // TODO: 這裏的entry需要聲明一下類型
  const entry = data.webkitGetAsEntry()

  if (entry?.isFile) {
    // 獲取文件對象
    const file = data.getAsFile()
    if (file !== null) {
      uploadFiles([file])
    }
  } else {
    // 遞歸獲取目錄下所有的文件對象
    const files = await traverseDirectory(entry)
    uploadFiles(files)
  }
}

const handleDrop = async (event: DragEvent) => {
  if (event.dataTransfer === null) {
    return
  }

  const items = event.dataTransfer.items

  for (const item of items) {
    await upload(item)
  }
}
</script>

為什麼不直接用event.dataTransfer.files?

event.dataTransfer.files 是一個 FileList 對象,包含了拖放事件中所有文件的列表。它非常適合處理單個或多個文件的上傳。
但是,如果用户拖放的是一個文件夾,event.dataTransfer.files 只會獲取文件夾中的文件,無法用來遞歸地獲取子文件夾中的文件和子文件夾。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.