原本使用的是ng-zorro中upload上传组件上传文件,可是后面上传文件过大,上传速度慢,要求改成切片上传。
原本的上传组件不适合开发需求,改成原生的input上传,添加了取消上传功能,html代码如下:
<div style="display: flex;align-items: center;justify-content: flex-start">
<div style="width: 30%">
<button nz-button nzType="primary" (click)="clickUpload()" [disabled]="progerssShow">
<i nz-icon nzType="plus" nzTheme="outline"></i>上传课件
</button>
<span class="operaTao" style="margin-left: 15px" (click)="cancelUpload()" [hidden]="!progerssShow">取消</span>
<input accept="application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document, audio/mp4,video/mp4,application/pdf,video/x-msvideo" (change)="inputFileChange($event)" type="file" id="fileImport" style="display: none">
</div>
<div style="width: 40%;position: relative;left: -80px;" [hidden]="!progerssShow">
<nz-progress [nzPercent]="fileProgress" nzStatus="active"></nz-progress>
</div>
</div>
逻辑部分代码如下:
/*上传文件点击,触发input的click事件*/
clickUpload() {
$('#fileImport').click();
this.isCancel = false;
}
/*选择文件,切片上传*/
inputFileChange(e): void {
this.firmwareFileList = null;
this.fileLast = null;
this.fileObj = null;
this.classSaveObj = new SaveExamObj();
this.examList = [];
const files = e.target.files;
if (files && files[0]) {
const file = files[0];
this.firmwareFileList = file;
// 根据文件大小进行切片,这里是当文件大于100M时,按照文件大小分成100片,小于时,切成每片1M
if (file.size > 1024*1024*100) {
this.bytesPerPiece = Math.floor(file.size / 100);
} else {
this.bytesPerPiece = 1024 * 1024 *1;
}
this.progerssShow = true;
this.fileProgress = 0;
let start = 0;
let index = 0;
setTimeout(() => {
this.loopSend(this.firmwareFileList, start, index); // 调用分片上传函数
}, 100);
e.target.value = '';
}
}
// 分片上传函数,这里调用后台接口需要和后端协商如何传参数,这里是没传一片,后端会返回下一片的序号,用于保存当前文件上传进度,使得文件上传如果中断,下次选择相同的文件时,继续之前的进度上传
loopSend(item, start, index) {
if (this.isCancel) { // 取消上传
return;
}
let that = this;
const size = item.size;
const finame = item.name;
that.totalPieces = Math.ceil(size / that.bytesPerPiece); //计算文件切片总数
const filekey = 'yxsource' + item.name + item.size + that.totalPieces;
const filekey1 = Md5.hashStr(filekey).toString();
if(start >= size){
return;
}//退出循环
let end = start + that.bytesPerPiece;
if(end > size) {
end = size;
}
var chunk = item.slice(start, end); //切割文件
var sliceIndex= index; //分片索引(第几个分片)
//存业务属性
var formData = new FormData();
formData.append("file", chunk); //文件分片
formData.append('moduleName', 'yxsource');
formData.append("fileName", finame);//文件名
formData.append("sliceIndex",sliceIndex.toString());//分片索引
formData.append("totalPieces",that.totalPieces.toString());//切片总数
formData.append('key', filekey1);
this.httpclient.post(this.uploadUrlMaterial, formData, {
responseType: 'json',
headers: new HttpHeaders({
Authorization: StorageUtil.getLocalStorage('token')
}),
}).subscribe(res => {
// @ts-ignore
if (res.status === StatusEnum.SUCCESS) {
// @ts-ignore
let sIdx = res.datas.sliceIndex; // 后端返回的下次上传的分片序号
if (Number.parseInt(sIdx) != -1) {
that.fileProgress = Math.floor(index / that.totalPieces * 100); // 上传进度条进度
index = Number.parseInt(sIdx);
start = index * that.bytesPerPiece;
that.loopSend(item, start, index)
} else {
// 文件上传完成===需要处理的地方
that.fileProgress = 100;
this.progerssShow = false;
}
} else {
this.fileProgress = 0;
this.progerssShow = false;
this.isCancel = true; // 是否取消
}
});
}
/*取消上传,只要不让循环继续就行*/
cancelUpload() {
this.isCancel = true;
this.fileProgress = 0;
this.progerssShow = false;
}
效果如下: