UI:
功能: 控制功能按钮在点击视频时出现,3s后自动消失,视频播放进度条可以拖动控制进度,有全屏和取消全屏功能,点击音量按钮出现音量控制条,可控制播放音量,不接触屏幕3s后随控制按钮一同消失。
html:
<div ref='videoContainer'
:class="['myvideo-box',fullScreenState ? 'fullscreen' : '']"
@mousemove='controlerShowControl(true)'
@mouseup='controlerShowControl(false)'
@click='controlerShowControl(true)'>
<div class='myvideo'>
<img v-show='posterShow' class='poster' :src='poster'/>
<video ref='video'
:class='[widthFix ? "widthFix" : "heightFix"]'
:poster="poster"
:muted="mutedState"
:autoplay = 'autoplay'
:src='videourl'
@ended='playEndControler(false)'
@timeupdate='playUpdate'
@loadedmetadata='setDuration'>
<source :src="videourl" type="video/mpg">
</video>
</div>
<transition name="fade">
<div class="controls" v-show='controlerShow'>
<img class="play"
@click = 'playControler'
v-show='controlerShow'
:src = "playState ? '../../common/imgs/pause.png' : '../../common/imgs/play.png'" alt="">
<!--进度条-->
<div class='controller'>
<span style='width: 100px;'>{{currentTime}}</span>
<div class="myvideo-progress"
:style='{"background":"linear-gradient(to right,#F25A0D 0,#F25A0D " + progress + ",#B7B6B6 " + progress + ",#B7B6B6 100%)"}'
ref='progress'
@mousedown.stop='progressOnDown'
@touchstart.stop='progressOnDown'
@mousemove.stop='progressOnMove'
@touchmove.stop='progressOnMove'
@mouseup.stop='progressOnUp'
@mouseout.stop='progressOnUp'
@touchend.stop='progressOnUp'>
<span class='circle-progress' :style='{left:progress}'></span>
</div>
<span style='width: 100px;'>{{duration}}</span>
<div class="voice-control">
<span class='voice-progressbox'
v-if='voiceProgressShow'
@mousedown.stop='voiceOnDown'
@touchstart.stop='voiceOnDown'
@mousemove.stop='voiceOnMove'
@touchmove.stop='voiceOnMove'
@mouseup.stop='voiceOnUp'
@touchend.stop='voiceOnUp'>
<span class='voice-progress'
:style='{"background":"linear-gradient(to top,#F25A0D 0,#F25A0D " + voiceProgress + ",#B7B6B6 " + voiceProgress + ",#B7B6B6 100%)"}'
ref='voiceProgress' >
<span class='voice-progress-dot' :style='{bottom:voiceProgress}'></span>
</span>
</span>
<img style='margin:0px 10px;' :src="mutedState ? '../../common/imgs/mute.png' : '../../common/imgs/sound.png'" @click='() => { this.voiceProgressShow = true }' alt="">
</div>
<img style='margin:0px 10px;' :src="fullScreenState ? '../../common/imgs/fullscreen-shrink.png' : '../../common/imgs/enlarge.png'"
class="fullscreen"
@click='toggleFullscreen'
alt="">
</div>
</div>
</transition>
</div>
css:
.myvideo-box {
position: relative;
display: inline-block;
text-align: center;
width: 90.3rem;
height: 55rem;
overflow: hidden;
}
.myvideo-box.fullscreen{
position:fixed;
left: 0;
top:0;
width: 100%;
height: 100%;
background-color: #000;
}
/* .myvideo中含video和poster(img)两个标签 */
.myvideo-box .myvideo{
position: relative;
width: 100%;
height: 100%;
}
.myvideo-box .myvideo .poster{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
.myvideo-box video.heightFix {
height: 100%;
}
.myvideo-box video.widthFix {
width: 100%;
}
.myvideo-box .controls {
width: 100%;
color: #fff;
font-size:35px;
height: 60px;
}
.myvideo-box .play{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
width: 8rem !important;
height: 8rem !important;
}
/* controller相比controls少了播放暂停的功能按钮 */
.myvideo-box .controls .controller{
position: absolute;
left: 0px;
/* bottom: 20px; */
width: 100%;
padding: 5px 18px;
bottom: 0px;
padding-bottom: 25px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-items: center;
background:linear-gradient(rgba(0,0,0,0) 0%,rgba(0,0,0,0.8) 80%,rgba(0,0,0,0.8) 100%);
}
.myvideo-box.fullscreen .controls .controller{
/* bottom: 50px; */
padding-bottom: 55px;
}
.myvideo-box .controller img {
height: 45px !important;
}
.myvideo-box .controller img:last-child {
height: 35px !important;
}
.myvideo-box.fullscreen .controller img {
width: 45px !important;
height: 45px !important;
cursor: pointer;
}
/* controller进度条 */
.myvideo-box .myvideo-progress {
display: inline-block;
width: 90%;
height: 6px;
line-height: 6px;
border-radius: 5px;
vertical-align: super;
position: relative;
}
.myvideo-box .myvideo-progress .circle-progress{
display:inline-block;
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #fff;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.myvideo-box .voice-control {
position: relative;
}
.myvideo-box .voice-control img{
position: relative;
top: 3px;
}
.myvideo-box .voice-control .voice-progressbox{
position: absolute;
left: 50%;
transform: translate(-50%);
top: -110px;
background-color: rgba(0,0,0,0.5);
width: 2rem;
border-radius: 5px;
padding: 10px 0px 0px;
}
.myvideo-box .voice-control .voice-progress{
position: relative;
/* top: 10px; */
display:inline-block;
width: 6px;
height: 80px;
border-radius: 3px;
background-color: #fff;
}
.myvideo-box .voice-progress .voice-progress-dot{
display:inline-block;
width: 16px;
height: 16px;
border-radius: 50%;
background-color: #fff;
position: absolute;
left: 50%;
transform: translateX(-50%);
}
/* controller淡入淡出 */
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
js:
props:{
videourl: String,
poster: String,
fullscreen: Boolean,
autoplay:Boolean
},
data: () => {
return {
playState:false,
voiceProgressShow:false,
voiceProgress:'0%',
voiceDrag:false,
currentTime:'00:00',
progress:'0%',
progressDrag:false,// 进度条是否被鼠标拖拽
duration:'00:00',
fullScreenState: false,
mutedState:false,
controlerShow:true,
controlerShowTimer:'',
widthFix:true,
}
},
methods:{
setDuration(){// 视频准备完成时执行
let video = this.$refs.video;
if (video.videoWidth > video.videoHeight) {
this.widthFix = true;
} else {
this.widthFix = false;
}
// 设置初始音量
this.voiceProgress = '50%';
video.volume = 0.5;
this.duration = this.formatTime(this.$refs.video.duration)
},
toggleFullscreen(){// 切换全屏
//this.fullScreenState = !this.fullScreenState;
if(this.isFullScreen()){
this.exitFullscreen()
} else {
this.requestFullscreen(document.querySelector('.myvideo-box'));
}
},
isFullScreen () {
return document.isFullScreen || document.mozIsFullScreen || document.webkitIsFullScreen
},
requestFullscreen(ele) {
// 全屏兼容代码
if (ele.requestFullscreen) {
ele.requestFullscreen();
} else if (ele.webkitRequestFullscreen) {
ele.webkitRequestFullscreen();
} else if (ele.mozRequestFullScreen) {
ele.mozRequestFullScreen();
} else if (ele.msRequestFullscreen) {
ele.msRequestFullscreen();
}
this.fullScreenState = true;
},
// 取消全屏
exitFullscreen() {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
}
this.fullScreenState = false;
},
controlerShowControl(show){// 控制controller的显示隐藏
if (show) {
clearTimeout(this.controlerShowTimer);
this.controlerShowTimer = setTimeout(() => {
if (this.playState) {
this.controlerShow = false;
this.voiceProgressShow = false;
}
},3000)
}
this.controlerShow = show;
},
playControler(){// 播放按钮点击事件
console.log('play')
let video = this.$refs.video;
if(video.paused || video.ended) {
video.play()
this.playState = true;
this.posterShow = false;
} else {
video.pause();
this.playState = false;
// clearTimeout(this.controlerShowTimer);
}
},
playEndControler(breakOff){
this.currentTime = '00:00';
this.progress = '0%';
this.playState = false;
this.posterShow = true;
video.currentTime = 0;
if(breakOff) {
let video = this.$refs.video;
if (!(video.paused || video.ended)) {
video.pause();
}
if (this.autoplay) {// 如果父组件传入自动播放为true
this.playState = true;
}
}
},
stopVideo(){
this.playState = false;
this.controlerShow = true;
let video = this.$refs.video;
if (!(video.paused || video.ended)) {
video.pause();
}
},
playUpdate(){// 视频播放时进度更新
if (this.$refs.video) {
let currentTime = this.$refs.video.currentTime;
let duration = this.$refs.video.duration;
let progress = currentTime / duration * 100;
this.currentTime = this.formatTime(currentTime);
this.progress = progress*0.996 +'%';
}
},
// 拖拽进度条相关
progressOnDown(e){
this.progressDrag = true;
this.updateprogress(e.pageX || e.changedTouches[0].pageX);
},
progressOnMove(e){
if (this.progressDrag) {
this.updateprogress(e.pageX || e.changedTouches[0].pageX);
}
},
progressOnUp(e){
if (this.progressDrag) {
this.progressDrag = false;
this.updateprogress(e.pageX || e.changedTouches[0].pageX);
}
},
updateprogress(ePageX) {// 更新进度条
let progressRect = this.$refs.progress.getBoundingClientRect();
var percent = 100 * (ePageX - progressRect.x) / progressRect.width;
if(percent > 100) {
percent = 100;
}
if(percent < 0) {
percent = 0;
}
this.progress = percent*0.996 + "%";
this.currentTime = this.formatTime(this.$refs.video.duration * percent / 100);
this.$refs.video.currentTime = this.$refs.video.duration * percent / 100;
},
voiceOnDown(e){
this.voiceDrag = true;
this.updateVoice(e.pageY || e.changedTouches[0].pageY);
this.controlerShowControl(true);
},
voiceOnMove(e){
if (this.voiceDrag) {
this.updateVoice(e.pageY || e.changedTouches[0].pageY);
this.controlerShowControl(true);
}
},
voiceOnUp(e){
if (this.voiceDrag) {
this.updateVoice(e.pageY || e.changedTouches[0].pageY);
this.voiceDrag = false;
this.controlerShowControl(true);
}
},
updateVoice(ePageY) {
let progressRect = this.$refs.voiceProgress.getBoundingClientRect();
// console.log(progressRect)
var percent = 100 * (progressRect.y + progressRect.height - ePageY) / progressRect.height;
if(percent > 100) {
percent = 100;
}
if(percent < 0) {
percent = 0;
this.mutedState = true;
} else {
this.mutedState = false;
}
this.voiceProgress = percent * 0.85 + "%";
this.$refs.video.volume = percent / 100;
},
formatTime(seconds) {
var minute = Math.floor(seconds / 60);
if(minute < 10) {
minute = "0" + minute;
}
var second = Math.floor(seconds % 60);
if(second < 10) {
second = "0" + second;
}
return minute + ":" + second;
},
},
mounted(){
if (this.autoplay) {
this.playState = true;
this.posterShow = false;
this.$nextTick(() => {
this.controlerShowTimer = setTimeout(() => {
this.controlerShow = false;
},5000)
})
}
document.addEventListener('mouseup',this.progressOnUp,false);
},
调用:
<my-video :videourl='videoUrl'
:poster='poster'
:fullscreen='false'
:autoplay='autopaly'
:fullscreen='fullscreen'></my-video>