自定义上传的方式
http-request 自定义上传的方式
<el-upload
v-show="isInitUploadStatus()"
ref="qUpload"
class="upload-main"
drag
:auto-upload="false"
accept=".zip,.bat"
action="-"
:http-request="handleUploadFile"
:headers="headers"
:show-file-list="false"
:before-upload="beforeFileUpload"
>
<i class="qax-icon-fillupload" />
<div class="q-upload__text">
<em>点击/拖拽</em> 上传文件
</div>
</el-upload>
/**
* 自定义文件上传
*/
async handleUploadFile(params) {
const chunkSize = 20 * 1024 * 1024; // 每个文件块大小为20MB
this.chunks = this.splitChunks(chunkSize, params.file);
// 发送文件块到服务器
await this.sendService(params);
},
-
之所以走,自定义文件上传的方式,是因为el-upload自带的上传方式,是直接上传,无法满足我们的需求。针对大文件的上传,会卡死页面。
-
自定义上传的参数,params,包含了所有的单个属性和方法。这里包括:on-success,on-error,on-progress等,使用方式和正常使用相同。只不过触发方式是在自定义函数里边触发;
-
params.onProgress(); // 调用的方法其实是,模板上定义的方法
-
-
下一步,就可以拿到File对象,进行文件切片上传了。
文件切片上传
// 切片
splitChunks(chunkSize, file) {
let chunks = [];
let cur = 0;
if (file.size > chunkSize) {
while (cur < file.size) {
chunks.push(file.slice(cur, cur + chunkSize));
cur += chunkSize;
}
} else {
chunks.push(file);
}
return chunks;
},
- 大于预定的文件大小,循环截取,储存在数组中。
- 小于预定的文件大小,直接存储,准备下一阶段的上传。
文件上传
// 发送到服务端
async sendService({file}) {
const {name, size} = file;
const {fileUid} = this.fileConfig;
const chunksLength = this.chunks.length;
let num = 0;
for (let i = 0; i < chunksLength; i++) {
const item = this.chunks[i];
try {
await this.$service.uploadChunkPost({
uuid: fileUid,
chunk: i,
chunks: chunksLength,
size: size,
file: item,
file_name: name,
});
num++;
if (num === chunksLength) { // 用于处理文件全部上传完成,进行合并的调用操作
await this.mergeFile();
}
} catch (error) {
console.error('Error uploading chunk:', error);
}
}
},
-
uuid,生成一个随机不重复的唯一标识。我用的uuid包。
-
import { v4 as uuidv4 } from 'uuid'; // 生成UUIDv4 const uuid = uuidv4(); // 转换为字符串并输出长度 const uuidString = uuid.replaceAll('-', '');
-
-
循环分片的数组,调用上传的接口。【这里的代码,这样写感觉不太好】思考: Permison
-
这里还有浏览器的请求数量限制, Web Worker
合并文件
async mergeFile() {
try {
// 调用文件合并接口
} catch (error) {
console.error('Error merging chunks:', error);
}
},
- 如上有一个判断是不是已经上传完成,上传完成之后,就可以调用合并接口了。
代码集合
- 就不合并起来了,反而不好看了。这里还有几个问题要思考优化的。Web Worker,循环请求。File对象。Blob。
- 上传文件之前的,大小和格式校验是必要的。
- 上传会伴随,上传状态,这个也会同步处理。
文件批量上传
自定义请求方式,轮训请求后端接口,可取消接口请求。
输入
获取到文件的fileList,支撑展示
:on-change="handleFileChange" handleFileChange,返回file和fileList
批量上传
const list = this.generatePromiseRequest();
Promise.all(list);
//-----------------------------------------//
// 单独封装上传参数,用于控制取消上传请求
generatePromiseRequest() {
const promiseList = [];
for (const element of this.tableData) {
const item = element;
const { file } = item;
// 文件校验
if (!this.filesCheck(file)) {
const {uploadEnabledState, uploadErrorMessage} = this.uploadFileCheckMap;
this.$set(item, 'uploadEnabledState', uploadEnabledState);
this.$set(item, 'uploadErrorMessage', uploadErrorMessage);
continue;
}
const param = new FormData();
param.append('file', file.raw);
const requestPendingList = this.$http
.post(
`url/xxxx/参数`,
param,
{
headers: { 'Content-Type': 'multipart/form-data' },
// 文件上传进度控制
onUploadProgress: (e) => {
const percentage = (e.loaded / e.total) * 100 || 0;
this.$set(item, 'percentage', percentage);
},
// 文件取消
cancelToken: new CancelToken((c) => {
item.cancelToken = c;
}),
}
)
.then((data) => {
if (data.status !== 10000) {
throw new Error();
}
this.handleSuccess(data, item);
})
.catch((e) => {
this.handleError(e, item);
});
promiseList.push(requestPendingList);
}
return promiseList;
},
取消文件上传
const CancelToken = axios.CancelToken;
// 文件取消
cancelToken: new CancelToken((c) => {
item.cancelToken = c;
}),