在本周,潘老师要求对文件上传功能进行一下修改,要求弹出一个弹窗并显示上传进度,开始的时候想着还觉得这是个挺高级的功能,现在才发现前人又一次帮我们铺好了路。
通用实现
标题是angular,但先介绍的方法却和angular无关,而是一个在js中都可以通用的方法——XMLHttpRequest
。
XMLHttpRequest
XMLHttpRequest 对象用于在后台与服务器交换数据。
XMLHttpRequest 对象是_开发者的梦想_,因为您能够:
- 在不重新加载页面的情况下更新网页
- 在页面已加载后从服务器请求数据
- 在页面已加载后从服务器接收数据
- 在后台向服务器发送数据
所有现代的浏览器都支持 XMLHttpRequest 对象。
关于它的详细内容可以查看这篇文档,这里就不在细说了。
XMLHttpREquest.upload.onprogress
回到正题,要实现文件上传进度很简单,upload.onprogress
事件回调方法可用于跟踪资源上传的进度,它的event参数对象包含两个重要的属性loaded和total。分别代表当前已上传的字节数(number of bytes)和文件的总字节数。既然知道了这两个属性,上传进度,上传速度等等不就都可以算出来了:
// 增加上传过程事件
xhr.upload.addEventListener('progress', (e: ProgressEvent) => {
// lengthComputable属性代表文件总大小是否可知。如果 lengthComputable 属性的值是 false,那么意味着总字节数是未知并且 total 的值为零。
if (e.lengthComputable) {
// 上传的百分比
const percentage = Math.round((e.loaded * 100) / e.total);
// 耗费的时间 , time 是开始的时间
const diff = new Date().getTime() - time;
// 上传的速度
speed = Math.round(e.loaded / diff * 1000);
// 剩余时间
eta = Math.ceil((e.total - e.loaded) / speed);
}
}, false);
注意事项
1.若是再浏览器的控制台中 new 一个XHR对象,并使用点运算符,可以发现有一个onprogress
事件监听器
虽然,这看着和我们用到的差不多,但这可不是我们需要的,
后者是用于加载资源时,而前者用于资源上传时
2.测试的时候最好网速慢一点,或者文件大一些,否着可能会出现看不出效果,一来就是百分百,因为xhr.upload.onprogress在上传阶段(即xhr.send()之后,xhr.readystate=2之前)触发,每50ms触发一次。
ps: 网速可以通过控制台设置
angular实现
后来才发现angular已经给我们封装,整体上都是差不多的
upload(file: File) {
if (!file) {
return;
}
// 创造请求对象
// reportProgress 告诉 HttpClient 监听并返回XHR progress events事件.
const req = new HttpRequest('POST', '/upload/file', file, {
reportProgress: true
});
// 产生一个 event 流
return this.http.request(req).subscribe((event: HttpEvent<{}>) => {
if (event.type === HttpEventType.UploadProgress) {
if (event.total > 0) {
// 计算上传的百分比
const percent = event.loaded / event.total * 100;
} } });
HttpEventType 是不同种类的 HttpEvent 的枚举类型(官方解释)
这是anular的官方demo可以参考。
原文地址:https://segmentfault.com/a/1190000021941638