小魚兒心語:當(dāng)人生讓你碰壁頭破血流時(shí),別害怕,沒有這些挫折,怎能練就一身鋼筋鐵骨,當(dāng)生活給你一百個(gè)理由哭泣時(shí),別沮喪,你就拿出一千個(gè)理由笑給它看。



廢話不多說,直接上代碼:
視頻上傳uploadvideo.vue組件(直接復(fù)制即可):
<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="預(yù)覽"
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
},
// 圖片數(shù)量限制
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"); // 上傳的圖片服務(wù)器地址
const headers = ref({ Authorization: "Bearer " + getToken() });
const fileList = ref([]);
const showTip = computed(
() => props.isShowTip && (props.fileType || props.fileSize)
);
const videoFlag = ref(false);
//是否顯示進(jìn)度條
const videoUploadPercent = ref("");
//進(jìn)度條的進(jìn)度
const isShowUploadVideo = ref(false);
//顯示上傳按鈕
const videoForm = ref({showVideoPath: []});
const isbackground = ref("");
watch(() => props.modelValue, val => {
if (val) {
// 首先將值轉(zhuǎn)為數(shù)組
const list = Array.isArray(val) ? val : props.modelValue.split(",");
// 然后將數(shù)組轉(zhuǎn)為對象數(shù)組
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)
}
// 上傳前l(fā)oading加載
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;
}
// 文件個(gè)數(shù)超出
function handleExceed() {
proxy.$modal.msgError(`上傳文件數(shù)量不能超過 ${props.limit} 個(gè)!`);
}
// 上傳成功回調(diào)
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;
}
})
}
// }
}
// 上傳結(jié)束處理
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();
}
// 預(yù)覽
function handlePictureCardPreview(file) {
dialogImageUrl.value = file.url;
dialogVisible.value = true;
}
// 對象轉(zhuǎn)成指定字符串分隔
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>
// 彈框中視頻上傳的組件引用
// 添加或修改不安全行為標(biāo)準(zhǔn)對話框
<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`是修改時(shí)用于回顯視頻的屬性
<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
}
// 查詢不安全行為標(biāo)準(zhǔn)列表
function getList() {
loading.value = true;
listStandard().then(response => {
standardList.value = response.rows;
// 拼接視頻地址,import.meta.env.VITE_APP_BASE_API 為接口請求的ip地址,根據(jù)實(shí)際情況獲取~
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
// 獲取詳情數(shù)據(jù)
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 = "修改不安全行為標(biāo)準(zhǔn)";
});
}
</script>
接下來給大家總結(jié)了video的標(biāo)簽,屬性,方法,事件的使用方法:
<video> 標(biāo)簽屬性:
src:視頻的URL
poster:視頻封面,沒有播放時(shí)顯示的圖片
preload:預(yù)加載
autoplay:自動播放
loop:循環(huán)播放
controls:瀏覽器自帶的控制條
width:視頻寬度
height:視頻高度
Html代碼:
<video ref=”media” src=”http://www.abc.com/test.mp4″ controls width=”400px” heigt=”400px”></video>
// 獲取標(biāo)簽
const media= this.$refs.media; ----vue2.0寫法
`或者`
const { proxy } = getCurrentInstance();
const media= proxy.$refs.media; ----vue3.0寫法
Js代碼:
// 錯(cuò)誤狀態(tài)
Media.error; //null:正常
Media.error.code; //1.用戶終止 2.網(wǎng)絡(luò)錯(cuò)誤 3.解碼錯(cuò)誤 4.URL無效
Media.currentSrc; //返回當(dāng)前資源的URL
Media.src = value; //返回或設(shè)置當(dāng)前資源的URL
Media.canPlayType(type); //是否能播放某種格式的資源
Media.networkState; //0.此元素未初始化 1.正常但沒有使用網(wǎng)絡(luò) 2.正在下載數(shù)據(jù) 3.沒有找到資源
Media.load(); //重新加載src指定的資源
Media.buffered; //返回已緩沖區(qū)域,TimeRanges
Media.preload; //none:不預(yù)載 metadata:預(yù)載資源信息 auto:
Media.currentTime = value; //當(dāng)前播放的位置,賦值可改變位置
Media.startTime; //一般為0,如果為流媒體或者不從0開始的資源,則不為0
Media.duration; //當(dāng)前資源長度 流返回?zé)o限
Media.paused; //是否暫停
Media.defaultPlaybackRate = value;//默認(rèn)的回放速度,可以設(shè)置
Media.playbackRate = value;//當(dāng)前播放速度,設(shè)置后馬上改變
Media.played; //返回已經(jīng)播放的區(qū)域,TimeRanges,關(guān)于此對象見下文
Media.seekable; //返回可以seek的區(qū)域 TimeRanges
Media.ended; //是否結(jié)束
Media.autoPlay; //是否自動播放
Media.loop; //是否循環(huán)播放
Media.play(); //播放
Media.pause(); //暫停
Media.controls;//是否有默認(rèn)控制條
Media.volume = value; //音量
Media.muted = value; //靜音
事件:
eventTester = function(e){
Media.addEventListener(e,function(){
console.log((new Date()).getTime(),e);
});
}
eventTester(“l(fā)oadstart”); //客戶端開始請求數(shù)據(jù)
eventTester(“progress”); //客戶端正在請求數(shù)據(jù)
eventTester(“suspend”); //延遲下載
eventTester(“abort”); //客戶端主動終止下載(不是因?yàn)殄e(cuò)誤引起),
eventTester(“error”); //請求數(shù)據(jù)時(shí)遇到錯(cuò)誤
eventTester(“stalled”); //網(wǎng)速失速
eventTester(“play”); //play()和autoplay開始播放時(shí)觸發(fā)
eventTester(“pause”); //pause()觸發(fā)
eventTester(“l(fā)oadedmetadata”); //成功獲取資源長度
eventTester(“l(fā)oadeddata”); //
eventTester(“waiting”); //等待數(shù)據(jù),并非錯(cuò)誤
eventTester(“playing”); //開始回放
eventTester(“canplay”); //可以播放,但中途可能因?yàn)榧虞d而暫停
eventTester(“canplaythrough”); //可以播放,歌曲全部加載完畢
eventTester(“seeking”); //尋找中
eventTester(“seeked”); //尋找完畢
eventTester(“timeupdate”); //播放時(shí)間改變
eventTester(“ended”); //播放結(jié)束
eventTester(“ratechange”); //播放速率改變
eventTester(“durationchange”); //資源長度改變
eventTester(“volumechange”); //音量改變
屬性列表:

媒介屬性: 一般用于js操作


