先给大家看看样式是否符合在考虑要不要copy,因为没有啥技术难度,就是样式,也没有考虑h265等别的兼容性
详情是有全屏按钮的,正常是没有全屏按钮
1.在component文件夹下创建一个Myvideo.vue的文件
2.在component文件夹的index.js中全局引入Myvideo组件
import MyVideo from './MyVideo/index.vue';
Vue.component('MyVideo', MyVideo);
我这里直接上代码了
<template>
<div class="videoBox" @click.stop="clickVideo">
<!-- :controls="isPlay ? true : false" -->
<!-- :poster="cover" 封面图 -->
<video
:loop="isDetails ? false : true"
x5-playsinline
playsinline="true"
x-webkit-airplay="allow"
webkit-playsinline="true"
x5-video-player-type="h5"
x5-video-player-fullscreen="true"
disablePictureInPicture="true"
:autoplay="isDetails ? true : false"
controlslist="nodownload noremoteplayback noplaybackrate"
:src="video"
ref="video"
@play="isPlay = true"
@pause="isPlay = false"
@timeupdate="timeUpdate"
></video>
<!-- 定位到播放位置 -->
<div class="position" v-if="targetTime" ref="targetTime">
上次播放至{{ targetTime }},已续播
</div>
<!-- 正在播放 -->
<div class="pause" ref="pause" v-if="isPlay">
<div class="time">{{ timeDisplay }}</div>
<div class="right">
<svg
t="1689131823093"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="7676"
width="20"
height="20"
>
<path
d="M426.666667 138.666667v746.666666a53.393333 53.393333 0 0 1-53.333334 53.333334H266.666667a53.393333 53.393333 0 0 1-53.333334-53.333334V138.666667a53.393333 53.393333 0 0 1 53.333334-53.333334h106.666666a53.393333 53.393333 0 0 1 53.333334 53.333334z m330.666666-53.333334H650.666667a53.393333 53.393333 0 0 0-53.333334 53.333334v746.666666a53.393333 53.393333 0 0 0 53.333334 53.333334h106.666666a53.393333 53.393333 0 0 0 53.333334-53.333334V138.666667a53.393333 53.393333 0 0 0-53.333334-53.333334z"
fill="#ffffff"
p-id="7677"
></path>
</svg>
<!-- 全屏按钮 -->
<svg
@click.stop="fullscreen"
v-if="isDetails"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-70 h-70"
color="#fff"
style="margin-left: 5rem"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15"
/>
</svg>
</div>
</div>
<!-- 暂停播放 -->
<div class="play" ref="play" v-else>
<div class="time">{{ timeDisplay }}</div>
<div class="right">
<svg
t="1689131454914"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="6652"
width="20"
height="20"
>
<path
d="M161.2 839.9v-654c0-56.1 60.7-91.1 109.3-63.1l566.3 327c48.6 28 48.6 98.1 0 126.2L270.4 903c-48.5 28-109.2-7.1-109.2-63.1z"
fill="#ffffff"
p-id="6653"
></path>
</svg>
<!-- 全屏按钮 -->
<svg
@click.stop="fullscreen"
v-if="isDetails"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-70 h-70"
color="#fff"
style="margin-left: 5rem"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15"
/>
</svg>
</div>
</div>
<!-- 时间条 -->
<div class="timeLine" :class="isPlay ? 'bottom' : 'top'">
<van-slider
v-model="sliderVal"
:min="0"
:max="sliderMax"
@change="dragend"
/>
</div>
<!-- 重新播放按钮 -->
<div class="replay" v-if="isReplay" @click="replay">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-100 h-100"
style="color: #fff"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M9 15L3 9m0 0l6-6M3 9h12a6 6 0 010 12h-3"
/>
</svg>
</div>
</div>
</template>
<script>
export default {
props: {
cover: {
typeof: String,
},
video: {
typeof: String,
},
// 详情页面的参数
isDetails: {
typeof: Boolean,
default: false,
},
time: {
typeof: String,
},
},
data() {
return {
// 是否正在播放
isPlay: false,
//总时长
duration: "00:00",
// 当前时间
timeDisplay: "00:00",
sliderMax: 0,
sliderVal: 0,
//播放时间
targetTime: "",
//重新播放
isReplay: false,
};
},
watch: {
isPlay() {
this.$nextTick(() => {
if (this.isPlay) {
this.$refs.pause.style.opacity = "1";
if (this.targetTime && this.$refs.targetTime) {
this.$refs.targetTime.style.opacity = "1";
}
setTimeout(() => {
if (this.$refs.pause) {
this.$refs.pause.style.opacity = "0";
}
if (this.targetTime && this.$refs.targetTime) {
this.$refs.targetTime.style.opacity = "0";
}
}, 1500);
} else {
this.$refs.play.style.opacity = "1";
// setTimeout(() => {
// this.$refs.play.style.opacity = "0";
// }, 1500);
}
});
},
time() {
console.log(this.time, Number(this.time) !== 0);
if (this.time && Number(this.time) !== 0) {
console.log(1);
this.$nextTick(() => {
this.$refs.video.currentTime = this.time;
this.targetTime = this.formatTime(this.time);
});
} else {
this.targetTime = "";
}
},
},
mounted() {
if (this.time && Number(this.time) !== 0) {
this.$nextTick(() => {
this.$refs.video.currentTime = this.time;
this.targetTime = this.formatTime(this.time);
});
} else {
this.targetTime = "";
}
},
methods: {
// 全屏
fullscreen() {
this.$refs.video.pause();
this.$emit("fullscreen");
// if (this.$refs.video.requestFullscreen) {
// this.$refs.video.requestFullscreen();
// } else if (this.$refs.video.webkitRequestFullscreen) {
// // 兼容性处理
// this.$refs.video.webkitRequestFullscreen();
// }
},
// 重新播放
replay() {
// 把按钮隐藏
this.isReplay = false;
// 将video时间转为0
this.$refs.video.currentTime = 0;
// 开始播放
this.$refs.video.play();
},
// 时间条变化
dragend(val) {
console.log(val);
this.$nextTick(() => {
// 赋值给video的播放时间
this.$refs.video.currentTime = val;
this.targetTime = "";
});
},
// 修改时间格式 00:00
formatTime(seconds) {
let minutes = Math.floor(seconds / 60);
let remainingSeconds = seconds % 60;
let formattedTime = "";
if (minutes < 10) {
formattedTime += "0";
}
formattedTime += minutes + ":";
if (remainingSeconds < 10) {
formattedTime += "0";
}
formattedTime += remainingSeconds;
return formattedTime;
},
// 播放时间
timeUpdate() {
if (!this.$refs.video) return;
this.timeDisplay = this.formatTime(
Math.floor(this.$refs.video.duration) -
Math.floor(this.$refs.video.currentTime)
);
this.sliderMax = Math.floor(this.$refs.video.duration);
this.sliderVal = Math.floor(this.$refs.video.currentTime);
if (this.isDetails) {
this.$emit("saveTime", this.sliderVal);
let over = Boolean(
Math.floor(this.$refs.video.duration) ===
Math.floor(this.$refs.video.currentTime)
);
if (over) {
this.isReplay = true;
} else {
this.isReplay = false;
}
}
},
clickVideo() {
if (this.isPlay) this.$refs.video.pause();
else this.$refs.video.play();
},
},
};
</script>
<style lang="scss" scoped>
:deep .van-slider__bar {
transition: all 1s;
}
.videoBox {
position: relative;
min-height: 200rem;
max-height: 390rem;
video {
width: 100%;
min-height: 200rem;
max-height: 390rem;
object-fit: cover;
object-position: center;
}
.position {
position: absolute;
bottom: 28rem;
left: -8rem;
font-size: 12rem;
color: white;
padding: 5rem 15rem;
background: rgba(34, 34, 34, 0.237) 0;
transform: scale(0.85);
transition: 0.5s;
}
.play {
z-index: 2;
position: absolute;
// bottom: 15rem;
// left: 15rem;
// top: 50%;
// left: 50%;
// transform: translate(-50%, -50%);
bottom: 0;
opacity: 1;
width: 100%;
height: 40rem;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 10rem 0 15rem;
transition: 0.8s;
background: linear-gradient(
to bottom,
transparent,
rgba(0, 0, 0, 0.273)
);
.time {
color: white;
font-size: 15rem;
padding-top: 4rem;
}
.right {
display: flex;
justify-content: space-between;
align-items: center;
}
}
.pause {
@extend .play;
}
.timeLine {
position: absolute;
z-index: 3;
width: 100%;
}
.bottom {
bottom: 0;
.van-slider {
height: 3rem;
}
:deep .van-slider__button {
display: none !important;
}
:deep .van-slider__bar {
background-color: #001fffe8;
}
}
.top {
bottom: 15rem;
width: 60%;
left: 21%;
.van-slider {
height: 5rem;
background-color: #ffffffa5;
}
:deep .van-slider__button {
width: 12rem;
height: 12rem;
}
:deep .van-slider__bar {
background-color: #001fffe8;
}
}
.replay {
position: absolute;
width: 50rem;
height: 50rem;
border-radius: 50%;
background-color: #0000007a;
display: flex;
justify-content: center;
align-items: center;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 3;
}
}
</style>