import genUUID from "../../utils/gen-uuid"; import { message } from "antd"; import classNames from "classnames" import { ReactNode, useEffect, useState } from "react" import './index.less' import React from "react"; /** * 文件或文件夹拖拽上传 * * 功能:可包裹在组件外部,形成大面积拖拽区域,目前需和uploadPanel组件配合使用,通过onDrop传文件列表参数, * * children: 被包裹的子组件 * className: 包裹外壳的样式 * onFileDrop: 向组件外传输解析后的文件列表,关联uploadPanel组件使用 * onContextMenu: 右键监听事件 * disabled: 禁用拖拽上传 * */ export interface DropFolder { name?: string //文件名 uid?: string //唯一性id,由gen-uuid生成 parentKey?: string //父文件夹的uid,根目录文件夹此项为空 } interface Iprops { children?: ReactNode, //子节点 className?: string, //类名 onFileDrop?: (fileList: any[], folderList: DropFolder[], fileCount?: number, folderCount?: number) => void, //上传文件后的回调 onContextMenu?: (e) => void //右键菜单 disabled?: boolean //是否可使用 } export default function UploadDragger({ children, className, onFileDrop, onContextMenu, disabled, }: Iprops) { const [onFileDragOver, setOnFileDragOver] = useState(false); // 拖拽进入的文件或文件夹列表,待处理 const [dataTransferItems, setDataTransferItems] = useState(); // 拖拽上传时 维持住上锁,等待所有文件处理完后一起给上传组件 const [uploadMaintainLock, setUploadMaintainLock] = useState(false); // 拖拽上传时异步分批处理完的文件存在这里,全部处理完后统一传给uploadfilelist const [dropUploadFileList, setDropUploadFileList] = useState([]); const [dropFolderList, setDropFolderList] = useState([]); const [fileCounter, setFileCounter] = useState(0); const [folderCounter, setFolderCounter] = useState(0); ///// 拖拽上传 let loadingIndicatorHide; useEffect(() => { if (!uploadMaintainLock) return; if (dataTransferItems == null) return; // 上锁并且拽入文件后开始处理 loadingIndicatorHide = message.loading('正在解析文件...', 0); setTimeout(loadingIndicatorHide, 500); onDrop(); }, [dataTransferItems, uploadMaintainLock]) useEffect(() => { // 处理完解析文件 解锁后,开启上传,等同于 beforeUpload if (dropUploadFileList.length === 0 && dropFolderList.length === 0) return; if (!uploadMaintainLock) { if (onFileDrop) { onFileDrop(dropUploadFileList, dropFolderList, fileCounter, folderCounter); } // setUploadFileList(dropUploadFileList); setDropUploadFileList([]); setDropFolderList([]); setFileCounter(0); setFolderCounter(0); } }, [uploadMaintainLock]) const onDrop = () => { let items = dataTransferItems; let length = items.length; for (let i = 0; i < length; i++) { let entry = items[i].webkitGetAsEntry(); traverseFileTree(entry); } } let uploadMaintainTimer$; const traverseFileTree = (item, path = "", folderKey = '') => { clearTimeout(uploadMaintainTimer$) path = path || ""; if (item?.isFile) { let fileItem = item; // let fileItem: FileSystemFileEntry = item; setFileCounter(pre => pre + 1); fileItem.file((file: File) => { clearTimeout(uploadMaintainTimer$); setDropUploadFileList(pre => { file['uid'] = genUUID(); file['parentKey'] = folderKey; return [...pre, file]; }); uploadMaintainTimer$ = setTimeout(() => { setUploadMaintainLock(false); }, 500) }) } else if (item?.isDirectory) { // let directoryItem: FileSystemDirectoryEntry = item; let directoryItem = item; var dirReader = directoryItem.createReader(); setFolderCounter(pre => pre + 1); let dir = { name: directoryItem.name, uid: genUUID(), parentKey: folderKey, } setDropFolderList(pre => { return [...pre, dir] }) uploadMaintainTimer$ = setTimeout(() => { setUploadMaintainLock(false); }, 500) dirReader.readEntries(function (entries) { for (var i = 0; i < entries.length; i++) { traverseFileTree(entries[i], path + item.name + "/", dir.uid); } }); } } return (
{ if (disabled) return; e.preventDefault(); // e.stopPropagation(); setOnFileDragOver(false) let items = e.dataTransfer.items; if (items == null || items.length === 0) return; if (items[0].kind !== 'file') return; setUploadMaintainLock(true) // 维持住不立即发生上传 setDataTransferItems(items); }} onDragEnter={e => { if (disabled) return; e.preventDefault(); // e.stopPropagation(); let items = e.dataTransfer.items; if (items == null || items.length === 0) return; if (items[0].kind !== 'file') return; setOnFileDragOver(true) }} onDragLeave={e => { if (disabled) return; e.preventDefault(); // e.stopPropagation(); setOnFileDragOver(false) }} onDragOver={e => { if (disabled) return; e.preventDefault(); // e.stopPropagation(); let items = e.dataTransfer.items; if (items == null || items.length === 0) return; if (items[0].kind !== 'file') return; setOnFileDragOver(true) }} onContextMenu={e => { if (onContextMenu) onContextMenu(e); }} > {!disabled && (
拖拽到此区域上传
)} {children}
) }