-
遇到问题:项目中需要上传500MB以上的视频。一开始使用上传组件el-upload,调用后台接口,但是出现了onprogress显示百分百后接口一直pending,过了很多秒后接口才通,如果遇到大文件的话,接口就会报超时。
-
解决办法:
使用阿里云OSS的分片上传。调用OSS时报No'Access-Control-Allow-Origin'的错误
一定要设置跨域规则!!!否则会报No'Access-Control-Allow-Origin'的错误
1. 创建oss.js文件
js
let OSS = require('ali-oss');
let client = new OSS({
region: '', // 填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
accessKeyId: '',
accessKeySecret: '',
bucket: '', // 填写Bucket名称
});
let cdnUrl = '' // 文件上传后的回调地址
export { client, cdnUrl };
2. 创建一个上传视频组件 VideoUpload.vue
js
<template>
<div class="component-upload-image">
<el-upload action="" :http-request="beforeUpload" class="avatar-uploader" :limit="limit"
:on-error="handleUploadError" :on-exceed="handleExceed" name="file" :show-file-list="false" :file-list="fileList"
ref="uploadRef">
<video v-if="videoForm.showVideoPath && !videoFlag" :src="videoForm.showVideoPath" class="avatar video-avatar"
controls="controls">
您的浏览器不支持视频播放
</video>
<!-- //i标签是上传前的那个+上传后隐藏 -->
<i v-else-if="!videoForm.showVideoPath && !videoFlag" class="el-icon-plus avatar-uploader-icon"></i>
<el-progress v-if="videoFlag == true" type="circle" :percentage="videoUploadPercent"
style="margin-top: 7px"></el-progress>
</el-upload>
<el-button v-if="isShowBtn && videoForm.showVideoPath" class="mt-20" plain round @click="handleDelete" size="small"
type="primary">重新上传<i class="el-icon-upload el-icon--right"></i></el-button>
</div>
</template>
<script>
import { client, cdnUrl } from "./oss";
export default {
props: {
value: [String, Object, Array],
// 图片数量限制
limit: {
type: Number,
default: 1,
},
// 大小限制(MB)
fileSize: {
type: Number,
default: 5120,
},
fileType: {
type: Array,
default: () => ["video/*"],
},
// 是否显示提示
isShowTip: {
type: Boolean,
default: true,
},
// 是否显示进度条
isShowUploadVideo: {
type: Boolean,
default: false,
},
// 是否显示重新上传按钮
isShowBtn: {
type: Boolean,
default: true,
},
},
data() {
return {
dialogImageUrl: "",
dialogVisible: false,
// hideUpload: false,
// baseUrl: process.env.VUE_APP_BASE_API,
// uploadImgUrl: process.env.VUE_APP_BASE_API + "/file/upload", // 上传的图片服务器地址
fileList: [],
videoForm: {
showVideoPath: "", //回显的变量
},
videoFlag: false,
videoUploadPercent: 0,
isCancel: false
};
},
watch: {
value: {
handler(val) {
if (val) {
this.videoForm.showVideoPath = val;
// 首先将值转为数组
const list = Array.isArray(val) ? val : this.value.split(",");
// 然后将数组转为对象数组
this.fileList = list.map((item) => {
if (typeof item === "string") {
item = { name: item, url: item };
}
return item;
});
} else {
this.fileList = [];
return [];
}
},
deep: true,
immediate: true,
},
},
computed: {
// 是否显示提示
showTip() {
return this.isShowTip && (this.fileType || this.fileSize);
},
},
methods: {
//自定义上传方法..
Upload(file) {
debugger;
//判断扩展名
const tmpcnt = file.file.name.lastIndexOf(".");
const exname = file.file.name.substring(tmpcnt + 1);
// 配置路径以及文件名称
const fileName = "files/" + file.file.uid + "." + exname;
const progress = (p, _checkpoint) => {
this.videoFlag = true;
this.videoUploadPercent = Number((Number(p) * 100).toFixed(1));
console.log(this.isCancel);
if (this.isCancel) {
console.log("取消上传");
client.cancel();
this.isCancel = false;
}
};
client.multipartUpload(fileName, file.file, {
progress,
// 设置并发上传的分片数量。
// parallel: 4,
// 设置分片大小。默认值为1 MB,最小值为100 KB。
partSize: 5 * 1024 * 1024,
}).then((res) => {
// console.log(res, "res");
this.videoFlag = false;
if (res.name) {
this.videoForm.showVideoPath = cdnUrl + res.name;
this.$emit("input", this.videoForm.showVideoPath, this.duration);
// this.loading.close();
} else {
this.$modal.msgError("上传视频失败,请重试");
// this.loading.close();
this.handleDelete();
}
})
.catch((err) => {
console.log(err);
if (err.name == 'cancel') {
this.$message('上传取消');
} else {
this.$modal.msgError(err);
}
this.handleDelete();
});
},
handleDelete() {
this.isCancel = true;
this.videoFlag = false;
this.$refs.uploadRef.clearFiles();
this.duration = 0;
this.videoForm.showVideoPath = "";
this.$emit("input", this.videoForm.showVideoPath, this.duration); // 清除已上传的文件
},
// 上传前
beforeUpload(file) {
var fileSize = file.file.size / 1024 / 1024 < this.fileSize; //控制大小 修改50的值即可
console.log(file.file.type);
if (
this.fileType.indexOf(file.file.type) == -1 //控制格式
) {
this.$modal.msgError(
`文件格式不正确, 请上传${this.fileType.join("/")}视频格式文件!`
);
return false;
}
if (!fileSize) {
this.$modal.msgError(`上传视频大小不能超过 ${this.fileSize} MB!`);
return false;
}
// 获取视频时长
var url = URL.createObjectURL(file.file);
var audioElement = new Audio(url);
var time;
var that = this;
audioElement.addEventListener("loadedmetadata", function () {
time = audioElement.duration; //时长为秒
that.duration = time;
});
// 一开始设置的全屏遮罩层,考虑到用户可能想取消上传,于是去除
// this.loading = this.$loading({
// lock: true,
// text: "上传中",
// background: "rgba(0, 0, 0, 0.7)",
// });
this.Upload(file);
},
// 文件个数超出
handleExceed() {
this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`);
},
// 上传失败
handleUploadError() {
this.$modal.msgError("上传失败,请重试");
// this.loading.close();
},
},
};
</script>
<style scoped lang="scss">
// .el-upload--picture-card 控制加号部分
::v-deep.hideUpload .el-upload--picture-card {
display: none;
}
::v-deep .el-upload--picture-card {
width: 104px;
height: 104px;
line-height: 104px;
}
::v-deep .el-upload-list--picture-card .el-upload-list__item {
width: 104px;
height: 104px;
}
.avatar-uploader-icon {
border: 1px dashed #d9d9d9 !important;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9 !important;
border-radius: 6px !important;
position: relative !important;
overflow: hidden !important;
}
.avatar-uploader .el-upload:hover {
border: 1px dashed #d9d9d9 !important;
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 300px;
height: 178px;
line-height: 178px;
text-align: center;
}
.avatar {
width: 300px;
height: 178px;
display: block;
}
</style>
在父组件中调用
js
<template>
<div class="app-container">
<el-dialog title="" :visible.sync="open" append-to-body @close="cancel">
<VideoUpload v-model="formClass.ossUrl" :limit="1" :fileType="fileType" :fileSize="5120" :isShowUploadVideo="true" @input="uploadVideo" ref="videoUploadRef" :isShowBtn="true"></VideoUpload>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
open: false,
formClass: {
ossUrl: "", //阿里云oss地址-视频
},
fileType: ["video/mp4"],
};
},
methods: {
submitForm() {},
cancel() {
if (this.$refs.videoUploadRef) {
this.$refs.videoUploadRef.handleDelete();
}
this.open = false;
},
},
};
</script>
原文链接:https://blog.csdn.net/wcy0112/article/details/136843100