videojs自己设置constro样式
效果图
下载videojs插件
npm install video.js --save
引入videojs插件
import videojs from "video.js";
import "video.js/dist/video-js.css";
import "videojs-contrib-hls";
htlm部分
<div class="videoIndex" :style="{ height }">
<div class="videoBox">
<video
ref="videoRef"
class="videoCss"
style="height: 100%; width: 100%"
h5-playsinline
x5-video-player-fullscreen="true"
webkit-playsinline="true"
playsinline="true"
></video>
<div class="controlBox" v-show="isControls">
<div class="playBackBox">
<img
class="playBack"
@click.stop="setPlayStatus(true)"
v-show="!playStatus"
src="../../assets/images/zt.svg"
alt=""
/>
<img
class="playBack"
@click.stop="setPlayStatus(false)"
v-show="playStatus"
src="../../assets/images/play.svg"
alt=""
/>
</div>
<div class="sliderBackBox" v-if="liveStatus == 'liveBack'">
<div class="curAllTime">
{{ handleVideoDuration(currentTime) }}
</div>
<div class="sliderBox" v-if="orientation == 'portrait'">
<van-slider
active-color="#FF9201"
inactive-color="#000"
bar-height="3px"
v-model="sliderValue"
@change.self="changeSlider"
/>
</div>
<div class="sliderBoxLandscape" v-if="orientation == 'landscape'">
<van-slider
vertical
active-color="#FF9201"
inactive-color="#000"
bar-height="3px"
v-model="sliderValue"
@change="changeSlider"
/>
</div>
<div class="curAllTime">
{{ handleVideoDuration(allTime) }}
</div>
<div class="speed" @click="speedShow = !speedShow">
{{ speed }}
</div>
</div>
<div class="rotateBox">
<img @click.stop="isLandscape" src="../../assets/images/lan.svg" />
</div>
</div>
<div class="speedBox" v-show="speedShow">
<div
class="speedNum"
v-for="item in speedActions"
:key="item.key"
@click.stop="setSpeend(item.key)"
>
{{ item.name }}
</div>
</div>
</div>
</div>
js部分
export default {
name: "MyVideo",
props: {
liveStatus: {
type: String,
default: "",
required: true,
},
videoSource: {
type: String,
default: "",
},
autoplay: {
type: Boolean,
default: false,
},
isControls: {
type: Boolean,
default: true,
},
height: {
type: String,
default: "200px",
},
},
data() {
return {
showPopover: false,
speedActions: [
{ name: "0.5X", key: "0.5" },
{ name: "1.0X", key: "1" },
{ name: "1.25X", key: "1.25" },
{ name: "1.5X", key: "1.5" },
{ name: "2.0X", key: "2.0" },
],
speed: "倍速",
speedShow: false,
player: null,
playStatus: false,
orientation: "portrait",
sliderValue: 0,
currentTime: "00:00:00",
allTime: "00:00:00",
sliderValue: 0,
mediaStream: null,
isEnd:'start'
};
},
mounted() {
const options = {
autoplay: false,
controls: false,
aspectRatio: "16:9",
muted: false,
preload: "auto",
sources: [
{
src: this.videoSource,
type: this.liveStatus == "liveIn" ? "application/x-mpegURL" : "",
},
],
};
this.player = videojs(this.$refs.videoRef, options, () => {});
this.player.on("loadedmetadata", this.getFirstFrame);
this.player.on("timeupdate", this.updateProgress);
this.player.on('play', this.onPlay);
this.player.on('pause', this.onPause);
this.player.on('ended', this.onEnded);
},
created() {},
methods: {
onPlay() {
this.playStatus = true;
this.$emit('playStatus',this.playStatus)
},
onPause() {
this.playStatus = false;
this.$emit('playStatus',this.playStatus)
},
handleVideoDuration(duration) {
duration = duration || 0;
return (
"" +
this.formatZero(~~(duration / 60 / 60)) +
":" +
this.formatZero(~~(duration / 60) % 60) +
":" +
this.formatZero(~~(duration % 60))
);
},
formatZero(time) {
return time > 9 ? time : "0" + time;
},
updateProgress() {
this.currentTime = this.player.currentTime();
this.sliderValue = (this.player.currentTime() / this.allTime) * 100;
if (this.sliderValue == 100) {
this.setPlayStatus(false);
}
},
getFirstFrame() {
this.allTime = this.player.duration();
const videoElement = this.player.el().getElementsByTagName('video')[0];
const canvas = document.createElement('canvas');
canvas.width = videoElement.videoWidth;
canvas.height = videoElement.videoHeight;
const context = canvas.getContext('2d');
setTimeout(() => {
context.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
let firstFrame = canvas.toDataURL();
this.player.setAttribute("poster", firstFrame);
}, 100);
},
isLandscape() {
let el = document.querySelector(".videoBox");
if (this.orientation == "portrait") {
this.orientation = "landscape";
el.style.width = "100vh";
el.style.height = "100vw";
el.style.position = "relative";
let isNewIphone =
window &&
window.screen.height >= 812 &&
window.devicePixelRatio >= 2 &&
!this.android;
el.style.top = "0";
el.style.left = "0";
el.style.zIndex = 99;
el.style.transform = "translateZ(100px)";
let w = document.body.clientWidth;
let h = document.body.clientHeight;
let cha = Math.abs(h - w) / 2;
el.style["transform"] =
"translate(-" + cha + "px," + cha + "px) rotate(90deg)";
el.style["-ms-transform"] =
"translate(-" + cha + "px," + cha + "px) rotate(90deg)";
el.style["-moz-transform"] =
"translate(-" + cha + "px," + cha + "px) rotate(90deg)";
el.style["-webkit-transform"] =
"translate(-" + cha + "px," + cha + "px) rotate(90deg)";
el.style["-o-transform"] =
"translate(-" + cha + "px," + cha + "px) rotate(90deg)";
} else if (this.orientation == "landscape") {
this.orientation = "portrait";
el.style.width = "100%";
el.style.height = this.height;
el.style.position = "relative";
el.style.top = 0;
el.style.transform = "none";
el.style.zIndex = 1;
el.style.transform = "translateZ(100px)";
}
},
changeSlider(value) {
this.player.currentTime((this.allTime / 100) * value);
},
setPlayStatus(val) {
this.playStatus = val;
if (val) {
this.player.play();
} else {
this.player.pause();
}
},
setSpeend(key) {
this.speed = key == "1" ? "倍速" : key + "X";
this.player.ready(function () {
this.playbackRate(parseFloat(key));
});
this.speedShow = false;
},
},
beforeDestroy() {
if (this.player) {
this.player.dispose();
}
},
};
css部分
.videoIndex {
width: 100%;
color: #000;
pointer-events: none;
.videoBox {
height: 100%;
display: flex;
position: relative;
.videoCss {
background: #000;
object-fit: cover;
}
::v-deep .vjs-fluid:not(.vjs-audio-only-mode) {
padding-top: 0 !important;
}
}
.controlBox {
width: 94%;
height: 43px;
position: absolute;
bottom: 0;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 3%;
pointer-events: auto;
background-image: linear-gradient(
180deg,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 0.3) 99%
);
.playBackBox {
width: 20px;
height: 20px;
}
.sliderBackBox {
flex: 1;
display: flex;
justify-content: space-between;
align-items: center;
.curAllTime {
font-size: 14px;
color: #fff;
margin: 0 6px;
}
.speed {
width: 40px;
font-size: 14px;
color: #fff;
margin-right: 6px;
}
.sliderBox {
flex: 1;
margin: 0 8px;
}
.sliderBoxLandscape {
height: calc(100vh - 350px);
transform: rotate(-90deg);
margin-left: 130px;
margin-right: 130px;
}
}
.rotateBox {
width: 20px;
height: 20px;
img {
width: 100%;
height: 100%;
}
}
::v-deep .van-slider__button {
width: 10px;
height: 10px;
}
}
.speedBox {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #fff;
width: 30%;
background: rgba(0, 0, 0, 0.8);
text-align: center;
border-radius: 4px;
pointer-events: auto;
}
}