前言:功能点概括:1、多选文件 2、选择文件夹 3、拖拽 4、选择后形成一个列表,列表里有一些信息 5、有进度条 6、控制并发数 7、可取消 8、展示统计信息
1. 交互实现
交互的目标是要拿到 file 对象。只要拿到 file 对象,就能通过网络上传。
1.1 如何选择多文件
给 input 添加 multiple 属性
<input type="file" multiple />
1.2 如何选择文件夹
给 input 添加 webkitdirectory、mozddirectory、odirectory 属性
<input type="file" webkitdirectory mozddirectory odirectory />
1.3 如何拖拽文件及文件夹
使用拖拽 API 触发事件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width" /> <title>document</title> <style> .container { width: 100%; height: 200px; border: 1px solid; } </style> </head> <body> <!-- 通过 $0.files 拿到所有文件File --> <input type="file" multiple /> <div class="container"></div> <script> const div = document.querySelector(".container"); // 都需要阻止默认行为,因为div是不允许任何东西拖拽到它上面的 // 当进入时触发 div.ondragenter = (e) => { console.log(1); e.preventDefault(); }; // 当有东西在盒子上时不断的触发 div.ondragover = (e) => { console.log(2); e.preventDefault(); }; // 当有东西放在盒子上时触发 div.ondrop = (e) => { e.preventDefault(); const items = e.dataTransfer.items; for (const item of items) { const entry = item.webkitGetAsEntry(); console.log(1, entry); if (entry.isFile) { // 处理文件:拿到File文件 entry.file((file) => { console.log(2, file); }); } else { const reader = entry.createReader(); reader.readEntries((entries) => { console.log(entries); }); } } }; </script> </body> </html>
2. 网络
网络部分用 XHR(axios) / fetch。
2.1 如何实现多文件上传
有两种方案,一种是所有文件合并到一次请求里。另一种单文件上传,需要和后端协商。我们一般采取第二种,这样有文件上传失败,也不会影响其他文件的上传。方便做进度跟踪,大文件切片,控制并发上传数。
2.2 如何实现进度追踪
上传进度跟踪 fetch 是实现不了的。只能实现下载的进度跟踪。我们可以通过 xhr.upload.onprogress 来控制上传进度跟踪。
2.3 如何实现取消上传
XHR 通过 xhr.abort() 直接取消。fetch 是通过控制器 AbortController 取消