真实网盘上传需隐藏原生file控件并用自定义ui触发,监听change获取文件;拖拽上传需e.preventdefault()阻止默认行为,drop事件获取文件;进度依赖xhr.upload.onprogress或fetch+readablestream;大文件须分块、断点续传、并发控制及服务端校验。

用 input type="file" 实现上传入口,但别直接暴露原生控件
网盘界面里看不到丑陋的“选择文件”按钮,是因为它被隐藏了,再用自定义按钮或拖拽区触发。关键不是禁用原生控件,而是把它透明盖在自定义 UI 下面:
- 给
<input type="file">加style="position: absolute; opacity: 0; z-index: -1;",让它不可见但可交互 - 点击你设计的“上传文件”按钮时,用 JavaScript 调用
fileInput.click() - 监听
change事件获取fileInput.files,而不是等表单 submit —— 这样才能做后续控制(比如校验、分块、进度) - 注意:
multiple属性必须加在<input>上,否则一次只能选一个
拖拽上传要用 dragover 和 drop 事件,不是靠 CSS
所谓“拖拽上传”,本质是浏览器原生支持的文件拖放 API,CSS 只负责视觉反馈,逻辑全在 JS 里:
- 必须阻止
dragover的默认行为,否则浏览器会打开文件(e.preventDefault()) -
drop事件的e.dataTransfer.files才是真正拖进来的文件列表,和<input>的files是同一类型对象 - 别只监听
drop就完事——用户可能中途取消拖拽,所以建议配合dragenter/dragleave做区域高亮 - 移动端不支持拖拽,这个交互纯桌面端有效;手机端仍要保留点击选择入口
上传状态要靠 XMLHttpRequest.upload.onprogress 或 fetch 的 ReadableStream,不能只靠后端返回
网盘的进度条不是上传完才显示“100%”,而是实时动的。这依赖前端主动监听传输过程,而非等响应:
- 用
XMLHttpRequest时,必须监听xhr.upload.onprogress,不是xhr.onprogress(后者不存在) - 用
fetch时,原生不支持上传进度,得用ReadableStream+pipeTo手动分片读取并上报,复杂度高;多数网盘仍用XMLHttpRequest保可控性 -
e.loaded和e.total并非 always 可用:某些 CORS 配置下e.lengthComputable为false,此时只能靠预估或后端回调更新进度 - 上传中禁用按钮、显示“暂停”“取消”按钮,这些状态切换必须和 xhr/fetch 实例生命周期严格绑定,否则容易出现重复提交或 cancel 失效
真实网盘不会用 form.submit(),因为没法控制分块、断点、并发
看到“上传完成”就以为结束了?真实网盘的上传链路远比表单提交复杂得多:
- 大文件(>10MB)必须切片:
file.slice(start, end)分块,每块单独发请求,带唯一块序号和文件标识(如 hash) - 断点续传靠服务端记录已收块:上传前先发
/check?fileId=xxx,返回已存在块列表,前端跳过重传 - 并发上传不是开 10 个 xhr 同时发——要限制并发数(常见 3–5),用 Promise 队列或
AbortController控制生命周期 - 后端合并不是简单拼接:要按块序号排序、校验每块 hash、最后整体再算一次文件 hash 防篡改
如果你只是想做个带上传按钮和进度条的“类网盘”界面,上面前三步够用了;但真要对标百度网盘那种体验,分块逻辑和服务端协议才是核心门槛,光靠 HTML 和 CSS 做不出来。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











