场景
vue + elementUi框架做后台管理系统时,使用到elementui中的Upload组件做单张图片或单个视频上传时。官网提供了单张图片上传和多图片上传,在其基础上又封装了一下,加入了上传时的进度条显示以及单个视频上传,封装到了一个组件中。
代码
uploadFile.vue
<template>
<div>
<el-upload
class="avatar-uploader"
:action="uploadUrl"
:headers="{ Authorization: token }"
:show-file-list="false"
:on-success="handleSuccess"
:before-upload="beforeUpload"
:on-progress="uploadProcess"
>
<div v-if="!fileFlag && fileType === 'image'">
<img v-if="fileUrl" :src="fileUrl" class="avatar" />
<i v-else class="el-icon-plus avatar-uploader-icon" />
</div>
<div v-if="!fileFlag && fileType === 'video'">
<video
v-if="fileUrl"
:src="fileUrl"
class="avatar-video"
controls="controls"
>
您的浏览器不支持视频播放
</video>
<i v-else class="el-icon-plus avatar-uploader-icon" />
</div>
<el-progress
v-if="fileFlag"
style="margin-top:10px;"
type="circle"
:percentage="uploadPercent"
/>
</el-upload>
</div>
</template>
<script>
export default {
props: {
token: {
type: String,
default: ""
},
uploadUrl: {
type: String,
required: true
},
fileType: {
type: String,
default: "image"
}
},
data() {
return {
fileUrl: "", // 上传成功后接口返回的地址
uploadPercent: 0, // 上传时进度条显示的进度
fileFlag: false // 显示文件还是进度条的标识
};
},
methods: {
// 上传成功的回调
handleSuccess(res, file) {
this.fileFlag = false;
this.uploadPercent = 0;
if (res.code === 200) {
this.fileUrl = res.data;
} else {
this.$message.error("视频上传失败,请重新上传!");
}
},
// 进度条
uploadProcess(event, file, fileList) {
this.fileFlag = true;
this.uploadPercent = Math.floor(event.percent);
},
beforeUpload(file) {
// 先空着在下面优化,对上传格式的限制,需要动态判断
}
}
};
</script>
props中的token
和uploadUrl
根据需要在父组件中传入,因为有时候后台接口要求上传文件时
需要在请求头headers里加入登录标识token
,uploadUrl
为上传文件的接口。fileType
传入image
或video
,在视图中就根据fileType
判断显示img图片标签还是video视频标签。
data中的字段含义可以在注释中看到。 下面是css代码:
<style lang="scss" scope>
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 148px;
height: 148px;
line-height: 148px;
text-align: center;
}
.avatar {
width: 148px;
max-height: 148px;
display: block;
}
.avatar-video {
width: 200px;
max-height: 200px;
display: block;
}
</style>
- 在父组件parent.vue中使用uploadFile.vue上传图片或视频 parent.vue
<uploadFile
:token="token"
:upload-url="uploadUrl"
file-type="video"
/>
<script>
import uploadFile from "./uploadFile.vue";
export default {
components: { uploadFile },
data() {
return {
token: "token123",
uploadUrl: process.env.VUE_APP_BASE_API + "/file/upload"
}
}
}
</script>
把token
和uploadUrl
换成自己的就可以使用上传功能了,file-type
不传值就默认为 "image"
。下面开始优化代码:
- 防止用户在传图片的地方上传了视频或其他文件,加入限制文件格式的代码 在 uploadFile.vue 中加入
beforeUpload(file) {
const isImage =
file.type === "image/jpeg" ||
file.type === "image/png" ||
file.type === "image/jpg";
const isVideo =
file.type === "video/mp4" ||
file.type === "video/avi" ||
file.type === "video/flv";
const isLt10M = file.size / 1024 / 1024 < 10;
if (!isLt10M) {
this.$message.error("上传文件大小不能超过 10MB!");
return false;
}
if (!isImage && this.fileType === "image") {
this.$message.error("上传文件格式有误!");
return false;
}
if (!isVideo && this.fileType === "video") {
this.$message.error("上传文件格式有误!");
return false;
}
},
- 如果需要回显,让子组件直接 uploadFile.vue 直接显示图片或视频,则再多加一个props参数。
父组件parent.vue中添加hasFile,如果需要回显直接传入需要回显的链接,不需要则为空
<SingleImageUpload
// ...
:has-file="hasFile"
/>
data() {
return {
// ...
hasFile: ""
};
},
子组件uploadFile.vue中接收参数
props: {
// ...
hasFile: {
type: String,
default: ""
}
},
子组件中使用watch监听,如果传入了值,就给fileUrl赋值传入的文件地址
watch: {
hasFile(val) {
if (val) {
this.fileUrl = val;
} else {
this.fileUrl = "";
}
}
}