组件:
<template><div class="upload-box"><div class="avatar-uploader-box"><!-- 图片预览 --><div :key="index" class="video-preview" v-for="(item, index) in videoList"><video v-if="item.videoLink" :src="`${videoBaseUrl}${item.videoLink}`" @mouseover.stop="item.isShowPopup = true" class="avatar">您的浏览器不支持视频播放</video><video v-else :src="item.url" @mouseover.stop="item.isShowPopup = true" class="avatar">您的浏览器不支持视频播放</video><!-- 显示查看和删除的按钮弹窗 --><div@mouseleave="item.isShowPopup = false"class="avatar-uploader-popup"v-show="(item.videoLink || item.url) && item.isShowPopup"><i @click="previewVideo(item)" class="el-icon-zoom-in"></i><i @click="deleteVideo(index)" class="el-icon-delete"></i></div></div><!-- 方框样式 --><el-upload:action="actionUrl":auto-upload="false":on-change="handleAvatarChange":show-file-list="false"class="avatar-uploader"ref="avatarUploader"v-show="uploadShow"><spanelement-loading-background="rgba(0, 0, 0, 0.8)"element-loading-spinner="el-icon-loading"element-loading-text="上传中"style="display:block;"v-loading="loading"><i class="el-icon-plus avatar-uploader-icon"></i></span></el-upload><!-- 上传提示文字样式 --><div class="upload-tip"><slot></slot></div></div><!-- 查看大图 --><el-dialog :visible.sync="dialogVisible" append-to-body center title="视频查看" :before-close="handleClose"><video :src="videoSrc" ref="video" controls alt width="100%">您的浏览器不支持视频播放</video></el-dialog></div>
</template><script>
export default {name: 'UploadVideo',components: {},props: {videos: {type: Array,default: function() {return []}},numLimit: {// 最大允许上传个数type: Number,default: 1},sizeLimit: {// 最大单文件大小type: Number,default: 50},videoBaseUrl: {// 已上传图片服务器路径type: String,required: true}},data() {return {loading: false,dialogVisible: false,videoList: [],videoSrc: '',actionUrl: ''}},computed: {uploadShow() {return this.videos.length < this.numLimit}},watch: {videos: {handler() {const isArray = Array.isArray(this.videos)if (isArray && this.videos.length > 0) {this.videos.map(item => {item.isShowPopup = false})this.videoList = JSON.parse(JSON.stringify(this.videos))} else {this.videoList = []}},deep: true,immediate: true}},created() {},methods: {// 上传之前beforeAvatarUpload(file) {return new Promise((resolve, reject) => {if (['video/mp4', 'video/ogg', 'video/flv', 'video/avi', 'video/wmv', 'video/rmvb', 'video/mov'].indexOf(file.raw.type) == -1) {// eslint-disable-next-line prefer-promise-reject-errorsreturn reject('请上传正确的视频格式!')}if (file.size / 1024 / 1024 > this.sizeLimit) {// eslint-disable-next-line prefer-promise-reject-errorsreturn reject(`视频大小不能超过${this.sizeLimit}M!`)}if (this.videoList.length === this.numLimit) {// eslint-disable-next-line prefer-promise-reject-errorsreturn reject(`最多上传${this.numLimit}个视频`)}resolve('符合表單規則')})},// 上传改变async handleAvatarChange(file, fileList) {try {await this.beforeAvatarUpload(file)this.uploadImgApi(file)} catch (e) {this.$message.warning(JSON.stringify(e))}},// 上传视频准备uploadImgApi(data) {console.log(data, 'upload**')const videoSrc = URL.createObjectURL(data.raw)this.videoList.push({videoFile: data,url: videoSrc,isShowPopup: false})this.$emit('change', this.videoList)},// 预览视频previewVideo(data) {if (data.videoLink) {this.videoSrc = `${this.videoBaseUrl}${data.videoLink}`} else {this.videoSrc = data.url}this.dialogVisible = true},// 删除视频deleteVideo(index) {this.$emit('delete', index)},handleClose() {const video = document.getElementsByTagName('video')[1]if (!video.paused) {video.currentTime = 0video.pause()}this.dialogVisible = false}}
}
</script><style lang="scss">
$width: 90px;
$height: 90px;.upload-box {.avatar-uploader-box {position: relative;display: flex;flex-direction: row;flex-wrap: wrap;padding-bottom: 20px;min-width: 350px;.avatar-uploader {.el-upload {width: $width;height: $height;border: 1px dashed #d9d9d9;border-radius: 6px;cursor: pointer;position: relative;overflow: hidden;&:hover {border-color: #409eff;}.el-loading-spinner {width: $width;height: $height;position: relative;display: flex;flex-direction: column;align-items: center;justify-content: center;margin-top: 0;top: 0;.el-loading-text {margin: 0;}}}.avatar-uploader-icon {font-size: 28px;color: #8c939d;width: $width;height: $height;line-height: $height;text-align: center;}}.video-preview {position: relative;padding-right: 20px;.avatar {width: $width;height: $height;display: block;border-radius: 6px;}.avatar-uploader-popup {position: absolute;top: 0;left: 0;z-index: 2;width: $width;height: $height;background: rgba($color: #000000, $alpha: 0.5);display: flex;justify-content: center;align-items: center;color: #fff;font-size: 20px;border-radius: 6px;i {width: 30%;text-align: center;padding: 0 5%;font-size: 24px;}}}.upload-tip {position: absolute;bottom: 0;left: 0;font-size: 12px;color: #606266;max-width: 350px;line-height: 20px;}}
}
</style>
页面引入:
import UploadVideo from '@c/UploadVideo'
components: { UploadVideo }
<upload-video:videos="videoInfo.allVideo":videoBaseUrl="IMAGEURL"@delete="deleteVideo"@change="getVideo" >
</upload-video>
data数据:
videoInfo: {allVideo: [],deleteVideo: []
}
视频上传:(此处只是上传到暂存区,真正上传是在提交表单时)
getVideo(event) {this.videoInfo.allVideo = event
}
视频删除:
deleteVideo(index) {const video = this.videoInfo.allVideo[index]if (video.videoLink) {this.videoInfo.deleteVideo.push(video)}this.videoInfo.allVideo.splice(index, 1)
}
在提交表单时上传:
uploadFiles() {const uploadList = []this.videoInfo.allVideo.map(item => {console.log(item, 'video')const videoFile = new FormData()if (!item.videoLink) {videoFile.append('file', item.videoFile.raw)videoFile.append('fileTag', 'video')uploadList.push(new Promise((resolve, reject) => {return ImgServe.uploadSingleFile(videoFile).then(res => {if (res.data.code === 200) {resolve(res.data.data)} else {this.$message('上传视频失败!')}})}))}})return Promise.all(uploadList)
}
*:分开上传是为了杜绝服务器脏数据
ImgServe.uploadSingleFile(videoFile)这儿是上传到服务器的接口,替换为自己的写法即可