关于vue+ElementUI中上传图片、视频或者文本文件等资源时,可以使用一个强大的组件来实现,下面直接上代码:
<template>
<div v-loading="loading" element-loading-text="文件上传中,请勿操作">
<el-upload
class="upload-demo"
ref="upload"
:action="action"
:file-list="fileList"
:on-success="uploadSuccess"
:http-request="uploadFile"
:on-error="uploadError"
:disabled="!canUploadFile"
:on-remove="uploadRemove"
:on-change="uploadChange"
:accept="accept"
:multiple="multiple"
>
<el-button
slot="trigger"
size="small"
type="primary"
:disabled="!canUploadFile"
>上传文件</el-button
>
<div slot="tip" class="el-upload__tip">
<el-button
slot="trigger"
size="small"
type="primary"
@click="clearUploadList"
>清空已上传文件</el-button
>
<el-progress :percentage="percentageNumber"></el-progress>
</div>
</el-upload>
</div>
</template>
<script>
import {
postAetheruploadInit,
postAetheruploadUpload,
} from "@/api/game/aid.js";
export default {
data() {
return {
action: "",
percentageNumber: 0,
fileList: [],
uploadName: "",
successUploadList: [],
loading: false,
};
},
props: {
// 可上传的文件个数 -1 为可以无限上传 不能为0
limit: {
type: Number,
default: 1,
},
// 限制上传的格式
accept: {
type: String,
default: "",
},
multiple: {
type: Boolean,
default: false
}
},
created() {
if (this.limit === 0) {
throw Error("上传文件限制不能为0");
}
},
computed: {
canUploadFile: {
get() {
return this.limit === -1 || this.limit > this.successUploadList.length;
},
},
},
methods: {
uploadError() {
this.loading = false;
this.clearUploadList();
},
isUploading() {
let res = false;
if (this.percentageNumber > 0 && this.percentageNumber < 100) {
this.$message.error("文件上传中,请勿关闭");
res = true;
}
return res;
},
uploadChange(file, fileList) {
this.fileList = fileList
},
async uploadFile(data) {
/*
记录一个elementui上传组件的坑
如果在这个函数中有报错它是不会被控制台所监控的
因为在这是一个加了async关键字的函数 async会将这个函数污染成一个Promise状态的函数
在upload组件内部应该有自己的对应Promise的catch机制 并且不会抛出到控制台上
所以当不出效果的时候就要去掉async 或者用try catch去自己捕获错误 而不使用elementui的错误机制
或者把async去掉改写成then catch的写法
补充一句纯函数才是yyds
*/
// 第一步先文件上传初始化
this.loading = true;
let { file } = data;
try {
let res = await postAetheruploadInit({
file_name: file.name,
file_size: file.size,
});
let { chunkSize, uploadBasename, uploadExt } = res;
let start = 0; // 每次上传的开始字节
let end = start + chunkSize; // 每次上传的结尾字节
let chunks = [];
let type = file.type;
while (start < file.size) {
// 根据长度截取每次需要上传的数据
// File对象继承自Blob对象,因此包含slice方法
let blob = file.slice(start, end, type);
chunks.push(blob);
start = end;
end = start + chunkSize;
}
// 循环发请求
let temp = 0;
for (let i = 0; i < chunks.length; i++) {
let item = chunks[i];
let formData = new FormData();
formData.append("file", item);
formData.append("upload_ext", uploadExt);
formData.append("chunk_total", chunks.length);
formData.append("chunk_index", i + 1);
formData.append("upload_basename", uploadBasename);
await postAetheruploadUpload(formData)
.then((res) => {
temp++;
this.percentageNumber = parseInt((temp / chunks.length) * 100);
if (res.uploadName) {
this.uploadName = res.uploadName;
this.successUploadList.push(this.uploadName);
this.$message.success("上传成功");
}
})
.catch((err) => {
// 如果上传失败 就清空进度条并且清空上传列表
this.clearUploadList();
this.$message.error("上传失败" + err);
});
}
if (this.canUploadFile) {
// 如果可以上传多个就清空进度条
// 清空列表和进度条状态
this.percentageNumber = 0;
}
} catch (error) {
this.clearUploadList();
this.$message.error("上传失败" + error);
}
this.loading = false;
},
uploadSuccess() {
this.$emit("uploadSuccess", this.uploadName);
},
uploadRemove(file, fileList) {
this.$emit("uploadRemove", file, fileList)
},
clearUploadList() {
// 清空列表和进度条状态
this.percentageNumber = 0;
this.$refs.upload.clearFiles();
this.uploadName = "";
this.successUploadList = [];
// 把空的name传出去
this.uploadSuccess();
// 触发清空事件
this.$emit("uploadClear")
},
},
};
</script>
<style>
</style>
说明:在使用这个组件的时候需要进行传值,大家可以先看看这个组件的代码再进行使用,传值也是非常简单的,如果不会的话可以去学习一下我之前发的有关vue传值的博客。