小鱼儿心语:当人生让你碰壁头破血流时,别害怕,没有这些挫折,怎能练就一身钢筋铁骨,当生活给你一百个理由哭泣时,别沮丧,你就拿出一千个理由笑给它看。
废话不多说,直接上代码:
视频上传uploadvideo.vue
组件(直接复制即可):
<template>
<div class="component-upload-image">
<el-upload
multiple
:action="uploadImgUrl"
:on-success="handleUploadSuccess"
:before-upload="handleBeforeUpload"
:limit="limit"
:on-error="handleUploadError"
:on-exceed="handleExceed"
:on-progress="uploadVideoProcess"
ref="imageUpload"
:before-remove="handleDelete"
:show-file-list="false"
:headers="headers"
:file-list="videoForm.showVideoPath"
:on-preview="handlePictureCardPreview"
:class="{ hide: videoForm.showVideoPath.length >= limit }"
:disabled="isdisabled"
>
<el-button type="primary">上传视频</el-button>
<!-- <video v-if="videoForm.showVideoPath !='' && !videoFlag"
v-for="(item,index) in videoForm.showVideoPath"
:key="index"
v-bind:src="item"
class="avatar video-avatar"
controls="controls"
style="width: 80%; height: 80%;">
您的浏览器不支持视频播放
</video> -->
<!-- <el-icon class="avatar-uploader-icon"><plus /></el-icon> -->
<el-progress v-if="videoFlag == true"
type="circle"
v-bind:percentage="videoUploadPercent"
style="margin-top:7px;"></el-progress>
</el-upload>
<!-- 自定义上传文件列表 -->
<div v-if="videoForm.showVideoPath.length > 0" style="width: 1300px;display: flex;flex-wrap: wrap;margin-top: 3%;">
<div v-for="(item, index) in videoForm.showVideoPath">
<!-- <img src="·······/视频路径" class="delete_icon" alt="" @click="deleteImg(item)"> -->
<video v-if="videoForm.showVideoPath !='' && !videoFlag"
v-bind:src="item.url"
class="avatar video-avatar"
controls="controls"
style="width: 70%;">
您的浏览器不支持视频播放
</video>
<p style="width: 100%;height: 20px;cursor: pointer;" :style="{background:isbackground}" v-on:mouseover="handleMouseOver" v-on:mouseout="headleMouseOut">
<span style="float: left;margin-top: -7px;">{{ item.name }}</span>
<!-- <el-icon class="Close" style="float: right;"></el-icon> -->
<el-icon :size="16" style="float: right;" @click="deleteImg(item,index)">
<Close />
</el-icon>
</p>
</div>
</div>
<!-- 上传提示 -->
<div class="el-upload__tip" v-if="showTip">
请上传
<template v-if="fileSize">
大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
</template>
<template v-if="fileType">
格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b>
</template>
的文件
</div>
<el-dialog
v-model="dialogVisible"
title="预览"
width="800px"
append-to-body
>
<img
:src="dialogImageUrl"
style="display: block; max-width: 100%; margin: 0 auto"
/>
</el-dialog>
</div>
</template>
<script setup>
import { getToken } from "@/utils/auth";
const props = defineProps({
modelValue: [String, Object, Array],
isdisabled: {
type: Boolean,
default: false
},
// 图片数量限制
limit: {
type: Number,
default: 5,
},
// 大小限制(MB)
fileSize: {
type: Number,
default: 5,
},
// 文件类型, 例如['png', 'jpg', 'jpeg']
fileType: {
type: Array,
default: () => ['video/mp4', 'video/ogg', 'video/flv', 'video/avi', 'video/wmv', 'video/rmvb', 'video/mov'],
},
// 是否显示提示
isShowTip: {
type: Boolean,
default: true
},
});
const { proxy } = getCurrentInstance();
const emit = defineEmits();
const number = ref(0);
const uploadList = ref([]);
const dialogImageUrl = ref("");
const dialogVisible = ref(false);
const baseUrl = import.meta.env.VITE_APP_BASE_API;
const uploadImgUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // 上传的图片服务器地址
const headers = ref({ Authorization: "Bearer " + getToken() });
const fileList = ref([]);
const showTip = computed(
() => props.isShowTip && (props.fileType || props.fileSize)
);
const videoFlag = ref(false);
//是否显示进度条
const videoUploadPercent = ref("");
//进度条的进度
const isShowUploadVideo = ref(false);
//显示上传按钮
const videoForm = ref({showVideoPath: []});
const isbackground = ref("");
watch(() => props.modelValue, val => {
if (val) {
// 首先将值转为数组
const list = Array.isArray(val) ? val : props.modelValue.split(",");
// 然后将数组转为对象数组
videoForm.value.showVideoPath = list.map(item => {
const filename = item.split('/')
const name = filename[filename.length-1]
if (typeof item === "string") {
if (item.indexOf(baseUrl) === -1) {
item = { name: name, url: baseUrl + item };
} else {
item = { name: name, url: item };
}
}
return item;
});
} else {
videoForm.value.showVideoPath = [];
return [];
}
},{ deep: true, immediate: true });
function handleMouseOver(){
isbackground.value = '#ede1e1'
}
function headleMouseOut(){
isbackground.value = ''
}
function deleteImg(row,index){
// videoForm.value.showVideoPath.forEach((item,index) => {
videoForm.value.showVideoPath.splice(index, 1);
// })
// videoForm.value.showVideoPath = videoForm.value.showVideoPath.fileter(item => item.name == row.name)
}
// 上传前loading加载
function handleBeforeUpload(file) {
// let isImg = false;
// if (props.fileType.length) {
// let fileExtension = "";
// if (file.name.lastIndexOf(".") > -1) {
// fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
// }
// isImg = props.fileType.some(type => {
// if (file.type.indexOf(type) > -1) return true;
// if (fileExtension && fileExtension.indexOf(type) > -1) return true;
// return false;
// });
// } else {
// isImg = file.type.indexOf("image") > -1;
// }
var fileSize = file.size / 1024 / 1024 < props.fileSize;
if (['video/mp4', 'video/ogg', 'video/flv', 'video/avi', 'video/wmv', 'video/rmvb', 'video/mov'].indexOf(file.type) == -1) {
proxy.$modal.msgError("请上传正确的视频格式");
return false;
}
if (!fileSize) {
proxy.$modal.msgError("视频大小不能超过${props.fileSize}MB");
return false;
}
isShowUploadVideo.value = false;
// if (!isImg) {
// proxy.$modal.msgError(
// `文件格式不正确, 请上传${props.fileType.join("/")}图片格式文件!`
// );
// return false;
// }
// if (props.fileSize) {
// const isLt = file.size / 1024 / 1024 < props.fileSize;
// if (!isLt) {
// proxy.$modal.msgError(`上传头像图片大小不能超过 ${props.fileSize} MB!`);
// return false;
// }
// }
// proxy.$modal.loading("正在上传图片,请稍候...");
number.value++;
}
function uploadVideoProcess(event, file, fileList) {
videoFlag.value = true;
videoUploadPercent.value = file.percentage.toFixed(0) * 1;
}
// 文件个数超出
function handleExceed() {
proxy.$modal.msgError(`上传文件数量不能超过 ${props.limit} 个!`);
}
// 上传成功回调
function handleUploadSuccess(res, file) {
if (res.code === 200) {
console.log(151,res)
isShowUploadVideo.value = true;
videoFlag.value = false;
videoUploadPercent.value = 0;
// uploadList.value.push({ name: res.fileName, url: res.fileName });
// fileList.value.push({ name: res.fileName, url: res.fileName });
videoForm.value.showVideoPath.push({ name: res.originalFilename, url: import.meta.env.VITE_APP_BASE_API + res.fileName });
emit("file", listToString(videoForm.value.showVideoPath));
uploadedSuccessfully();
} else {
number.value--;
proxy.$modal.closeLoading();
proxy.$modal.msgError(res.msg);
proxy.$refs.imageUpload.handleRemove(file);
uploadedSuccessfully();
}
}
// 删除图片
function handleDelete(file) {
console.log(166,fileList.value.map(f => f.name).toString(),file)
// const findex = fileList.value.map(f => f.name).toString().indexOf(file.name);
// console.log(168,findex)
// if (findex > -1 && fileList.value.length == number.value) {
if(fileList.value.length>0){
fileList.value.forEach((item,index) => {
console.log(172,item)
if(item.url.indexOf(file.response.fileName)!=-1){
fileList.value.splice(index, 1);
console.log(170,fileList.value.length)
emit("update:modelValue", listToString(fileList.value));
emit("file", listToString(fileList.value));
return false;
}
})
}
// }
}
// 上传结束处理
function uploadedSuccessfully() {
if (number.value > 0 && videoForm.value.showVideoPath.length === number.value) {
// fileList.value = fileList.value.filter(f => f.url !== undefined).concat(uploadList.value);
// fileList.value = uploadList.value
// console.log(175,fileList.value,uploadList.value)
// uploadList.value = [];
// number.value = 0;
emit("update:modelValue", listToString(videoForm.value.showVideoPath));
emit("file", listToString(videoForm.value.showVideoPath));
// proxy.$modal.closeLoading();
}
}
// 上传失败
function handleUploadError() {
proxy.$modal.msgError("上传图片失败");
proxy.$modal.closeLoading();
}
// 预览
function handlePictureCardPreview(file) {
dialogImageUrl.value = file.url;
dialogVisible.value = true;
}
// 对象转成指定字符串分隔
function listToString(list, separator) {
let strs = "";
separator = separator || ",";
for (let i in list) {
if (undefined !== list[i].url && list[i].url.indexOf("blob:") !== 0) {
strs += list[i].url.replace(baseUrl, "") + separator;
}
}
return strs != "" ? strs.substr(0, strs.length - 1) : "";
}
</script>
<style scoped lang="scss">
// .el-upload--picture-card 控制加号部分
:deep(.hide .el-upload--picture-card) {
display: none;
}
</style>
父组件引用**完整流程**
:
<template>
<div class="app-container">
// 表格中视频的展示
<el-table v-loading="loading" :data="standardList" @selection-change="handleSelectionChange">
<el-table-column label="视频" align="center" prop="unsafeJzsp" width="100">
<template #default="scope">
<video :src="scope.row.unsafeJzsp"
class="avatar video-avatar"
controls="controls"
style="width: 100%;">
</video>
</template>
</el-table-column>
</el-table>
// 弹框中视频上传的组件引用
// 添加或修改不安全行为标准对话框
<el-dialog :title="title" v-model="open" width="50%" append-to-body>
<el-form ref="standardRef" :model="form" :rules="rules" label-width="120px" inline>
<el-form-item label="矫正视频" prop="unsafeJzsp">
// `modelValue`是修改时用于回显视频的属性
<uploadvideo v-model="form.unsafeJzsp" style="width: 970px;" @file="getvideo" :modelValue="form.unsafeJzsp"></uploadvideo>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
// 接口为公共配置,引用即可,也可直接使用接口地址
import { listStandard, getStandard, delStandard, addStandard, updateStandard } from "@/api/unsafe/standard";
const { proxy } = getCurrentInstance();
const standardList = ref([]);
const data = reactive({
form: {}
});
const { form } = toRefs(data);
// 上传视频后视频组件传递过来的方法,获取上传的视频文件名
function getvideo(e){
form.value.unsafeJzsp = e
}
// 查询不安全行为标准列表
function getList() {
loading.value = true;
listStandard().then(response => {
standardList.value = response.rows;
// 拼接视频地址,import.meta.env.VITE_APP_BASE_API 为接口请求的ip地址,根据实际情况获取~
standardList.value.forEach(item => {
item.unsafeJzsp = import.meta.env.VITE_APP_BASE_API + item.unsafeJzsp
})
loading.value = false;
});
}
/** 修改按钮操作 */
function handleUpdate(row) {
const _unsafeBzId = row.unsafeBzId || ids.value
// 获取详情数据
getStandard(_unsafeBzId).then(response => {
form.value = response.data;
// 拼接视频地址,使提交的视频正?;叵哉故? form.value.unsafeJzsp = import.meta.env.VITE_APP_BASE_API + form.value.unsafeJzsp
open.value = true;
title.value = "修改不安全行为标准";
});
}
</script>
接下来给大家总结了video的标签,属性,方法,事件的使用方法:
<video> 标签属性:
src:视频的URL
poster:视频封面,没有播放时显示的图片
preload:预加载
autoplay:自动播放
loop:循环播放
controls:浏览器自带的控制条
width:视频宽度
height:视频高度
Html代码:
<video ref=”media” src=”http://www.abc.com/test.mp4″ controls width=”400px” heigt=”400px”></video>
// 获取标签
const media= this.$refs.media; ----vue2.0写法
`或者`
const { proxy } = getCurrentInstance();
const media= proxy.$refs.media; ----vue3.0写法
Js代码:
// 错误状态
Media.error; //null:正常
Media.error.code; //1.用户终止 2.网络错误 3.解码错误 4.URL无效
Media.currentSrc; //返回当前资源的URL
Media.src = value; //返回或设置当前资源的URL
Media.canPlayType(type); //是否能播放某种格式的资源
Media.networkState; //0.此元素未初始化 1.正常但没有使用网络 2.正在下载数据 3.没有找到资源
Media.load(); //重新加载src指定的资源
Media.buffered; //返回已缓冲区域,TimeRanges
Media.preload; //none:不预载 metadata:预载资源信息 auto:
Media.currentTime = value; //当前播放的位置,赋值可改变位置
Media.startTime; //一般为0,如果为流媒体或者不从0开始的资源,则不为0
Media.duration; //当前资源长度 流返回无限
Media.paused; //是否暂停
Media.defaultPlaybackRate = value;//默认的回放速度,可以设置
Media.playbackRate = value;//当前播放速度,设置后马上改变
Media.played; //返回已经播放的区域,TimeRanges,关于此对象见下文
Media.seekable; //返回可以seek的区域 TimeRanges
Media.ended; //是否结束
Media.autoPlay; //是否自动播放
Media.loop; //是否循环播放
Media.play(); //播放
Media.pause(); //暂停
Media.controls;//是否有默认控制条
Media.volume = value; //音量
Media.muted = value; //静音
事件:
eventTester = function(e){
Media.addEventListener(e,function(){
console.log((new Date()).getTime(),e);
});
}
eventTester(“loadstart”); //客户端开始请求数据
eventTester(“progress”); //客户端正在请求数据
eventTester(“suspend”); //延迟下载
eventTester(“abort”); //客户端主动终止下载(不是因为错误引起),
eventTester(“error”); //请求数据时遇到错误
eventTester(“stalled”); //网速失速
eventTester(“play”); //play()和autoplay开始播放时触发
eventTester(“pause”); //pause()触发
eventTester(“loadedmetadata”); //成功获取资源长度
eventTester(“loadeddata”); //
eventTester(“waiting”); //等待数据,并非错误
eventTester(“playing”); //开始回放
eventTester(“canplay”); //可以播放,但中途可能因为加载而暂停
eventTester(“canplaythrough”); //可以播放,歌曲全部加载完毕
eventTester(“seeking”); //寻找中
eventTester(“seeked”); //寻找完毕
eventTester(“timeupdate”); //播放时间改变
eventTester(“ended”); //播放结束
eventTester(“ratechange”); //播放速率改变
eventTester(“durationchange”); //资源长度改变
eventTester(“volumechange”); //音量改变
属性列表:
媒介属性: 一般用于js操作