完整代码,手写得代码比较笨重,可以借鉴一下思路
<template>
<div @mousemove.stop="topMove" style="width: 100%; height: 100%">
<div
:style="
'width:' +
myVideoWidth +
';height: ' +
myVideoHeight +
';position: relative;'
"
@mousemove.stop="mousemove"
>
<video
controls
ref="video_dom"
id="myVideo"
:style="
'width:' +
myVideoWidth +
';height: ' +
myVideoHeight +
';object-fit: fill;'
"
controlsList="nodownload"
>
<source src="./2024416-817024.mp4" type="video/mp4" />
Your browser does not support the video tag.
</video>
<div
ref="progress_bar2"
class="progress_bar"
:style="'position: absolute; top:' + top + 'rem;width:' + width + ';'"
v-show="show"
@mousemove="progressMove"
>
<div class="progress_barzk" @mousemove.stop="progressBarzk">
<div
ref="pda"
class="progress_barzk-A"
@mousemove.stop="elProgressMove"
@mousedown.stop="startTimer"
@mouseup.stop="clearTimer"
>
<div
class="el-progress-bar"
:style="
'width:' +
percentage +
'%; height: 100%; background: #ff6699;border-radius: 0.625rem;'
"
></div>
<img
v-if="biliDetermine"
:style="
'position: absolute;top:-0.4275rem;left: ' +
percentage +
'%;z-index:1;'
"
src="../../assets/image/bilibili.png"
class="bilibili"
/>
</div>
</div>
<div class="progress_bar_2">
<img
class="progress_bofang"
src="../../assets/image/bofang.png"
@click="clickPlay"
v-if="fal"
/>
<img
v-else
class="progress_bofang"
src="../../assets/image/bofang_1.png"
@click="clickSuspend"
/>
<div class="play_time_contrast">
<div>
{{
currentTime.toString().length < 5
? currentTime.toString().padStart(5, "0").replace(".", ":")
: currentTime.toString()
}}
</div>
<div>/</div>
<div>
{{
totalTime.toString().length < 5
? totalTime.toString().padStart(5, "0").replace(".", ":")
: totalTime.toString().replace(".", ":")
}}
</div>
</div>
<div class="barrage">
<div>
<span
@click="switchBarrage"
v-if="switchDetermine"
class="barrage_svg1"
>
<svg
xmlns="http://www.w3.org/2000/svg"
data-pointer="none"
viewBox="0 0 24 24"
:width="20"
:height="20"
>
<path
fill-rule="evenodd"
d="M11.989 4.828c-.47 0-.975.004-1.515.012l-1.71-2.566a1.008 1.008 0 0 0-1.678 1.118l.999 1.5c-.681.018-1.403.04-2.164.068a4.013 4.013 0 0 0-3.83 3.44c-.165 1.15-.245 2.545-.245 4.185 0 1.965.115 3.67.35 5.116a4.012 4.012 0 0 0 3.763 3.363l.906.046c1.205.063 1.808.095 3.607.095a.988.988 0 0 0 0-1.975c-1.758 0-2.339-.03-3.501-.092l-.915-.047a2.037 2.037 0 0 1-1.91-1.708c-.216-1.324-.325-2.924-.325-4.798 0-1.563.076-2.864.225-3.904.14-.977.96-1.713 1.945-1.747 2.444-.087 4.465-.13 6.063-.131 1.598 0 3.62.044 6.064.13.96.034 1.71.81 1.855 1.814.075.524.113 1.962.141 3.065v.002c.01.342.017.65.025.88a.987.987 0 1 0 1.974-.068c-.008-.226-.016-.523-.025-.856v-.027c-.03-1.118-.073-2.663-.16-3.276-.273-1.906-1.783-3.438-3.74-3.507-.9-.032-1.743-.058-2.531-.078l1.05-1.46a1.008 1.008 0 0 0-1.638-1.177l-1.862 2.59c-.38-.004-.744-.007-1.088-.007h-.13Zm.521 4.775h-1.32v4.631h2.222v.847h-2.618v1.078h2.618l.003.678c.36.026.714.163 1.01.407h.11v-1.085h2.694v-1.078h-2.695v-.847H16.8v-4.63h-1.276a8.59 8.59 0 0 0 .748-1.42L15.183 7.8a14.232 14.232 0 0 1-.814 1.804h-1.518l.693-.308a8.862 8.862 0 0 0-.814-1.408l-1.045.352c.297.396.572.847.825 1.364Zm-4.18 3.564.154-1.485h1.98V8.294h-3.2v.98H9.33v1.43H7.472l-.308 3.453h2.277c0 1.166-.044 1.925-.12 2.277-.078.352-.386.528-.936.528-.308 0-.616-.022-.902-.055l.297 1.067.062.005c.285.02.551.04.818.04 1.001-.067 1.562-.419 1.694-1.057.11-.638.176-1.903.176-3.795h-2.2Zm7.458.11v-.858h-1.254v.858h1.254Zm-2.376-.858v.858h-1.199v-.858h1.2Zm-1.199-.946h1.2v-.902h-1.2v.902Zm2.321 0v-.902h1.254v.902h-1.254Z"
clip-rule="evenodd"
fill="#fff"
></path>
<path
fill="#00AEEC"
fill-rule="evenodd"
d="M22.846 14.627a1 1 0 0 0-1.412.075l-5.091 5.703-2.216-2.275-.097-.086-.008-.005a1 1 0 0 0-1.322 1.493l2.963 3.041.093.083.007.005c.407.315 1 .27 1.354-.124l5.81-6.505.08-.102.005-.008a1 1 0 0 0-.166-1.295Z"
clip-rule="evenodd"
></path>
</svg>
</span>
<span @click="switchBarrage" v-else class="barrage_svg1">
<svg
xmlns="http://www.w3.org/2000/svg"
data-pointer="none"
viewBox="0 0 24 24"
:width="20"
:height="20"
>
<path
fill="#fff"
fill-rule="evenodd"
d="m8.085 4.891-.999-1.499a1.008 1.008 0 0 1 1.679-1.118l1.709 2.566c.54-.008 1.045-.012 1.515-.012h.13c.345 0 .707.003 1.088.007l1.862-2.59a1.008 1.008 0 0 1 1.637 1.177l-1.049 1.46c.788.02 1.631.046 2.53.078 1.958.069 3.468 1.6 3.74 3.507.088.613.13 2.158.16 3.276l.001.027c.01.333.017.63.025.856a.987.987 0 0 1-1.974.069c-.008-.23-.016-.539-.025-.881v-.002c-.028-1.103-.066-2.541-.142-3.065-.143-1.004-.895-1.78-1.854-1.813-2.444-.087-4.466-.13-6.064-.131-1.598 0-3.619.044-6.063.13a2.037 2.037 0 0 0-1.945 1.748c-.15 1.04-.225 2.341-.225 3.904 0 1.874.11 3.474.325 4.798.154.949.95 1.66 1.91 1.708a97.58 97.58 0 0 0 5.416.139.988.988 0 0 1 0 1.975c-2.196 0-3.61-.047-5.513-.141A4.012 4.012 0 0 1 2.197 17.7c-.236-1.446-.351-3.151-.351-5.116 0-1.64.08-3.035.245-4.184A4.013 4.013 0 0 1 5.92 4.96c.761-.027 1.483-.05 2.164-.069Zm4.436 4.707h-1.32v4.63h2.222v.848h-2.618v1.078h2.431a5.01 5.01 0 0 1 3.575-3.115V9.598h-1.276a8.59 8.59 0 0 0 .748-1.42l-1.089-.384a14.232 14.232 0 0 1-.814 1.804h-1.518l.693-.308a8.862 8.862 0 0 0-.814-1.408l-1.045.352c.297.396.572.847.825 1.364Zm-4.18 3.564.154-1.485h1.98V8.289h-3.2v.979h2.067v1.43H7.483l-.308 3.454h2.277c0 1.166-.044 1.925-.12 2.277-.078.352-.386.528-.936.528-.308 0-.616-.022-.902-.055l.297 1.067.062.004c.285.02.551.04.818.04 1.001-.066 1.562-.418 1.694-1.056.11-.638.176-1.903.176-3.795h-2.2Zm7.458.11v-.858h-1.254v.858H15.8Zm-2.376-.858v.858h-1.199v-.858h1.2Zm-1.199-.946h1.2v-.902h-1.2v.902Zm2.321 0v-.902H15.8v.902h-1.254Zm3.517 10.594a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm-.002-1.502a2.5 2.5 0 0 1-2.217-3.657l3.326 3.398a2.49 2.49 0 0 1-1.109.259Zm2.5-2.5c0 .42-.103.815-.286 1.162l-3.328-3.401a2.5 2.5 0 0 1 3.614 2.239Z"
clip-rule="evenodd"
></path>
</svg>
</span>
<svg
xmlns="http://www.w3.org/2000/svg"
data-pointer="none"
viewBox="0 0 24 24"
:width="20"
:height="20"
>
<path
fill-rule="evenodd"
fill="#fff"
d="m15.645 4.881 1.06-1.473a.998.998 0 1 0-1.622-1.166L13.22 4.835a110.67 110.67 0 0 0-1.1-.007h-.131c-.47 0-.975.004-1.515.012L8.783 2.3A.998.998 0 0 0 7.12 3.408l.988 1.484c-.688.019-1.418.042-2.188.069a4.013 4.013 0 0 0-3.83 3.44c-.165 1.15-.245 2.545-.245 4.185 0 1.965.115 3.67.35 5.116a4.012 4.012 0 0 0 3.763 3.363c1.903.094 3.317.141 5.513.141a.988.988 0 0 0 0-1.975 97.58 97.58 0 0 1-5.416-.139 2.037 2.037 0 0 1-1.91-1.708c-.216-1.324-.325-2.924-.325-4.798 0-1.563.076-2.864.225-3.904.14-.977.96-1.713 1.945-1.747 2.444-.087 4.465-.13 6.063-.131 1.598 0 3.62.044 6.064.13.96.034 1.71.81 1.855 1.814.075.524.113 1.962.141 3.065v.002c.005.183.01.07.014-.038.004-.096.008-.189.011-.081a.987.987 0 1 0 1.974-.069c-.004-.105-.007-.009-.011.09-.002.056-.004.112-.007.135l-.002.01a.574.574 0 0 1-.005-.091v-.027c-.03-1.118-.073-2.663-.16-3.276-.273-1.906-1.783-3.438-3.74-3.507-.905-.032-1.752-.058-2.543-.079Zm-3.113 4.703h-1.307v4.643h2.2v.04l.651-1.234c.113-.215.281-.389.482-.509v-.11h.235c.137-.049.283-.074.433-.074h1.553V9.584h-1.264a8.5 8.5 0 0 0 .741-1.405l-1.078-.381c-.24.631-.501 1.23-.806 1.786h-1.503l.686-.305c-.228-.501-.5-.959-.806-1.394l-1.034.348c.294.392.566.839.817 1.35Zm-1.7 5.502h2.16l-.564 1.068h-1.595v-1.068Zm-2.498-1.863.152-1.561h1.96V8.289H7.277v.969h2.048v1.435h-1.84l-.306 3.51h2.254c0 1.155-.043 1.906-.12 2.255-.076.348-.38.523-.925.523-.305 0-.61-.022-.893-.055l.294 1.056.061.005c.282.02.546.039.81.039.991-.065 1.547-.414 1.677-1.046.11-.631.175-1.883.175-3.757H8.334Zm5.09-.8v.85h-1.188v-.85h1.187Zm-1.188-.955h1.187v-.893h-1.187v.893Zm2.322.007v-.893h1.241v.893h-1.241Zm.528 2.757a1.26 1.26 0 0 1 1.087-.627l4.003-.009a1.26 1.26 0 0 1 1.094.63l1.721 2.982c.226.39.225.872-.001 1.263l-1.743 3a1.26 1.26 0 0 1-1.086.628l-4.003.009a1.26 1.26 0 0 1-1.094-.63l-1.722-2.982a1.26 1.26 0 0 1 .002-1.263l1.742-3Zm1.967.858a1.26 1.26 0 0 0-1.08.614l-.903 1.513a1.26 1.26 0 0 0-.002 1.289l.885 1.492c.227.384.64.62 1.086.618l2.192-.005a1.26 1.26 0 0 0 1.08-.615l.904-1.518a1.26 1.26 0 0 0 .001-1.288l-.884-1.489a1.26 1.26 0 0 0-1.086-.616l-2.193.005Zm2.517 2.76a1.4 1.4 0 1 1-2.8 0 1.4 1.4 0 0 1 2.8 0Z"
clip-rule="evenodd"
></path>
</svg>
</div>
</div>
<el-icon class="full_screen" @click="fullScreen"
><FullScreen
/></el-icon>
</div>
</div>
</div>
<div></div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
let video_dom = ref();
let Width = `${600 / 16}rem`;
let Height = `${500 / 16}rem`;
let myVideoWidth = ref(Width);
let myVideoHeight = ref(Height);
let top = ref();
let width = ref();
let progress_bar2 = ref();
let fal = ref<boolean>(true);
let show = ref<boolean>(false);
let percentage = ref(0); //进度条
let moveDetermine = ref<boolean>(false); //长按单击判断
let biliDetermine = ref<boolean>(false); //进度条bilibuli图标是否显示
let switchDetermine = ref<boolean>(false);
let currentTime = ref<string | number>("00:00");
let totalTime = ref<string | number>("00:00");
let clientY: any;
let timer: any;
let clientTime = ref(0);
let pda = ref();
const setTop = () => {
setTimeout(() => {
const videoDisplayHeight = video_dom.value.clientHeight;
const progressBarHeight = progress_bar2.value.clientHeight;
top.value = (videoDisplayHeight - progressBarHeight) / 16;
width.value = "100%";
}, 100);
};
const startTimer = () => {
moveDetermine.value = true;
};
const clearTimer = () => {
moveDetermine.value = false;
};
const progressBarzk = () => {
biliDetermine.value = true;
};
const elProgressMove = (event: any) => {
let b = (event.clientX / pda.value.clientWidth) * 100; //鼠标滑动距离
let a = video_dom.value.duration * (b / 100); //播放开始时间
if (moveDetermine.value) {
percentage.value = b;
clientTime.value = a;
}
pda.value.addEventListener("click", () => {
event.stopPropagation();
if (moveDetermine.value) {
moveDetermine.value = false;
return;
}
percentage.value = b;
video_dom.value.currentTime = a;
video_dom.value.play();
});
};
//打开弹幕
const switchBarrage = () => {
switchDetermine.value = !switchDetermine.value;
};
const mousemove = () => {
setTop();
setTimeout(() => {
show.value = true;
}, 100);
};
const topMove = () => {
setTimeout(() => {
show.value = false;
}, 100);
biliDetermine.value = false;
};
const progressMove = () => {
clearInterval(timer);
show.value = true;
biliDetermine.value = false;
moveDetermine.value = false;
};
//播放视频
const clickPlay = () => {
video_dom.value.play();
fal.value = !fal.value;
// progressBar();
};
//暂停视频
const clickSuspend = () => {
fal.value = !fal.value;
video_dom.value.pause();
};
//展开全屏
const fullScreen = async () => {
if (
!document.fullscreenElement
// &&
// !document.mozFullScreenElement &&
// !document.webkitFullscreenElement &&
// !document.msFullscreenElement
) {
if (document.documentElement.requestFullscreen) {
// document.documentElement.requestFullscreen();
myVideoWidth.value = "100vw";
myVideoHeight.value = "100vh";
document.documentElement.requestFullscreen();
setTop();
}
// else if (document.documentElement.mozRequestFullScreen) {
// document.documentElement.mozRequestFullScreen();
// } else if (document.documentElement.webkitRequestFullscreen) {
// document.documentElement.webkitRequestFullscreen();
// } else if (document.documentElement.msRequestFullscreen) {
// document.documentElement.msRequestFullscreen();
// }
} else {
// 如果当前页面已处于全屏状态,则退出全屏
if (document.exitFullscreen) {
document.exitFullscreen();
myVideoWidth.value = Width;
myVideoHeight.value = Height;
setTop();
}
// else if (document.mozCancelFullScreen) {
// document.mozCancelFullScreen();
// } else if (document.webkitExitFullscreen) {
// document.webkitExitFullscreen();
// } else if (document.msExitFullscreen) {
// document.msExitFullscreen();
// }
}
};
//退出全屏
const exitFullScreen = () => {
document.addEventListener("fullscreenchange", exitHandler);
document.addEventListener("webkitfullscreenchange", exitHandler);
document.addEventListener("mozfullscreenchange", exitHandler);
document.addEventListener("MSFullscreenChange", exitHandler);
function exitHandler() {
if (!document.fullscreenElement) {
myVideoWidth.value = Width;
myVideoHeight.value = Height;
setTop();
}
}
};
const videoDomMousemove = () => {
video_dom.value.addEventListener("mousemove", (event: any) => {
// const controls = video_dom.value.controls;
const rect = video_dom.value.getBoundingClientRect();
if (event.clientY >= rect.bottom - 40) {
// console.log("鼠标移到进度条上");
} else if (event.clientY < rect.bottom - 40) {
// console.log("鼠标离开进度条");
moveDetermine.value = false;
}
clientY = event.clientY;
clearInterval(timer);
timer = setInterval(() => {
if (clientY == event.clientY) {
show.value = false;
}
}, 2000);
});
};
const loadedmetadata = () => {
video_dom.value.addEventListener("loadedmetadata", function () {
//加载数据
// console.log("视频原始宽度:", video_dom.value.videoWidth);
// console.log("视频原始高度:", video_dom.value.videoHeight);
//视频的总长度
totalTime.value = (video_dom.value.duration / 60).toFixed(2);
});
};
const timeupdate = () => {
video_dom.value.addEventListener("timeupdate", function () {
if (!moveDetermine.value) {
currentTime.value = (video_dom.value.currentTime / 60).toFixed(2);
const currentTime2 = video_dom.value.currentTime;
const duration = video_dom.value.duration;
percentage.value = (currentTime2 / duration) * 100;
if (percentage.value == 100) {
fal.value = true;
}
}
});
};
onMounted(() => {
videoDomMousemove();
exitFullScreen();
loadedmetadata();
setTop();
timeupdate();
video_dom.value.addEventListener("play", function () {
//播放开始执行的函数
console.log("开始播放");
fal.value = false;
});
video_dom.value.addEventListener("playing", function () {
//播放中
console.log("播放中");
fal.value = false;
});
video_dom.value.addEventListener("waiting", function () {
//加载
console.log("加载中");
});
video_dom.value.addEventListener("pause", function () {
//暂停开始执行的函数
console.log("暂停播放");
fal.value = true;
});
video_dom.value.addEventListener(
"ended",
function () {
//结束
console.log("播放结束");
},
false
);
});
</script>
<style lang="scss" scoped>
@import "./index.scss";
video::-webkit-media-controls {
display: none;
}
</style>
css样式
@keyframes bilibili {
from {
width: 1rem;
height: 0rem;
}
to {
width: 1rem;
height: 1rem;
}
}
@keyframes progressBar {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.progress_bar {
// background-color: red;
height: 3.125rem;
display: flex;
justify-content: center;
flex-direction: column;
animation: progressBar 0.3s ease-out;
.full_screen {
width: 1rem;
height: 1rem;
background-color: #fff;
}
.progress_barzk {
width: 100%;
display: flex;
align-items: center;
padding: 0.375rem 0.375rem;
box-sizing: border-box;
.progress_barzk-A {
width: 100%;
height: 0.5rem;
position: relative;
background-color: rgba(51, 51, 51, 0.5);
border-radius: 0.625rem;
.bilibili {
width: 1rem;
height: 1rem;
animation: bilibili 1s;
// filter: brightness(10);
}
}
}
.progress_bar_2 {
display: flex;
align-items: center;
.progress_bofang {
width: 1.5rem;
height: 1.5rem;
filter: brightness(10); /* 通过 hue-rotate 滤镜旋转颜色 */
}
.play_time_contrast {
margin-left: 0.625rem;
color: #fff;
font-size: 0.875rem;
min-width: 5.5rem;
display: flex;
justify-content: space-between;
align-items: center;
}
.barrage {
min-width: 6.25rem;
display: flex;
margin-left: 1.875rem;
.barrage_svg1 {
margin-right: 0.375rem;
}
}
}
}