Files
learning-system-mobile/components/video-player/video-player.vue
2024-06-05 09:54:46 +08:00

417 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view id="xvideoPlayer-box" class="video-box">
<video id="xvideoPlayer" style="width: 100%;"
:src="url"
:controls="false"
:enable-play-gesture="false"
:initial-time="initPlayingTime"
@error="error"
@touchend="onTouchend"
@play="onPlay"
@pause="onPause"
@ended="onEnded"
@timeupdate="onTimeUpdate"
@fullscreenchange="onFullScreen"
@loadeddata="onLoad"
@loadedmetadata="onMetaLoad"
@controlstoggle="onControlsToggle"
></video>
<view id="xplayer-control" >
<view class="process-container" v-if="contrlShow">
<view class="controller-play">
<image :src="require(playing? './images/pause.png':'./images/play.png')" @click.stop='videoOpreation'/>
</view>
<view class="currtime">{{currtime}}</view>
<view class='slider-container'>
<slider :disabled="!drag" @change.stop="sliderChange" @changing="sliderChanging" step="1" :value="sliderValue" backgroundColor="#9f9587" activeColor="#d6d2cc" block-color="#FFFFFF" block-size="12"/>
</view>
<view class="druationTime">{{druationTime}}</view>
<view class="druationTime">
<view id="myVideoSpeed" class="player-speed btn-speed">
<view @click="showSpeedCtrl">{{videoSpeed === 1 ? '倍速' : `${videoSpeed}x`}}</view>
<view class="speed-control" v-if="speedListShow">
<view class="speed-control-list">
<view class="li"
v-for="item in speedList"
:key="item"
@click="changeSpeed(item)"
:data-value="item"
:class="{'current': videoSpeed === Number(item)}">
{{ item }}x
</view>
</view>
</view>
</view>
</view>
<view class="controller-screen">
<image :src="require(fullScreenFlag? './images/back.png':'./images/full.png')" @click.stop='fullScreen'/>
</view>
</view>
</view>
</view>
</template>
<script>
import {mapGetters} from 'vuex'
import studyUtil from '@/utils/study.js';
export default {
props: {
url:{
type: String,
require: true
},
watermark:{
type: Boolean,
default: true
},
name:{
type: String,
default: ''
},
drag:{
type: Boolean,
default: true
},
inittime:{//默认播放的位置,第几秒
type: Number,
default: 0
},
},
data() {
return {
contrlShow:false,//是否显示控制条
contrlShowTimeout:null,//显示控制条句柄
videoContext:null,//播放器
fullScreenFlag: false,//是否全屏
currtime:'00:00',//当前播放时间 字符串 计算后
druationTime:'00:00',//总时间 字符串 计算后
initPlayingTime:0,//指定播放的时间位置
sliderValue: 0, //控制进度条slider的值
updateState: true, //防止视频播放过程中导致的拖拽失效
playing:false,//是否在播放中
curVideo:{
duration:0
},
touchNum:0,
speedListShow:false,
speedList:["2.0", "1.5", "1.25", "1.0", "0.75", "0.5"],
videoSpeed: 1.0, // 当前倍速:
};
},
computed: {
...mapGetters(['userInfo']),
},
watch:{
url(newVal,oldVal){
this.videoContext.stop();
this.playing=false;
},
inittime(newVal,oldVal){
this.initPlayingTime=newVal;
}
},
mounted() {
this.initPlayingTime=this.inittime;
this.videoContext=uni.createVideoContext("xvideoPlayer", this);
},
methods: {
// 全屏+退出全屏
fullScreen(){
if(this.fullScreenFlag){
this.videoContext.exitFullScreen();
this.fullScreenFlag=false;
}else{
this.videoContext.requestFullScreen();
this.fullScreenFlag=true;
}
},
// 根据秒获取时间
formatSeconds(a) {
var hh = parseInt(a/3600);
var mm = parseInt((a-hh*3600)/60);
if(mm<10) mm = "0" + mm;
var ss = parseInt((a-hh*3600)%60);
if(ss<10) ss = "0" + ss;
if(hh<10) hh = hh == 0?'':`0${hh}:`;
var length = hh + mm + ":" + ss;
if(a>=0){
return length;
}else{
return "00:00";
}
},
changeSpeed(e) {
// 获取选择的倍速
let value = e;
this.videoSpeed = Number(value);
this.videoContext.playbackRate(this.videoSpeed);
studyUtil.setVideoSpeed(this.videoSpeed);
this.speedListShow=false;
},
showSpeedCtrl(){
if(this.speedListShow){
this.speedListShow=false;
}else{
this.speedListShow=true;
}
},
//开始+暂停
videoOpreation() {
this.playing ? this.videoContext.pause() : this.videoContext.play();
this.playing= !this.playing;
},
// 播放进度变化时触发event.detail = {currentTime, duration} 。触发频率 250ms 一次
videoUpdate(e) {
let duration=this.curVideo.duration;
let sliderValue = e.detail.currentTime / duration * 100;
let second=sliderValue / 100 * duration;
if (this.updateState) { //判断拖拽完成后才触发更新,避免拖拽失效
this.sliderValue=sliderValue;
this.$emit('progress',this.sliderValue);
}else{
}
this.druationTime = this.formatSeconds(duration);
//console.log(this.druationTime,'this.druationTime');
this.currtime = this.formatSeconds(second);
},
//拖动过程中触发的事件
sliderChanging(e) {
//拖拽过程中,不允许更新进度条
this.updateState= false;
},
// 拖动slider完成后触发
sliderChange(e) {
var duration=this.curVideo.duration;
var second=e.detail.value / 100 * duration;
if (duration) { //完成拖动后,计算对应时间并跳转到指定位置
this.videoContext.seek(second);
this.sliderValue= e.detail.value,
this.updateState= true //完成拖动后允许更新滚动条
this.druationTime = this.formatSeconds(duration);
this.currtime = this.formatSeconds(second);
}
},
onFullScreen(e) {
this.fullScreenFlag=e.detail.fullScreen;
let divId='videowatermark';//水印
let full=e.detail.fullScreen;
let divControlId='xplayer-control';
let box=document.getElementById('xvideoPlayer-box');
let control=document.getElementById(divControlId);
let $this=this;
setTimeout(() => {
var div = document.getElementById("xvideoPlayer");
var div1 = div.firstChild;
//水印
if(full){
if($this.watermark){
var div3 = document.createElement("div");
div3.id =divId;
div3.setAttribute("class", "fullmark");
div3.innerHTML='';
for(var i=0;i<4;i++){
div3.innerHTML+='<div style="color:#ffffff;width: 40%;height: 155px;padding-left:60px;padding-top:50px; display: flex;justify-content: center; transform: rotate(-36deg);font-size:20px;">'+$this.userInfo.name+$this.userInfo.code+'</div>';
}
div3.style.cssText = "position:absolute;pointer-events: none; width: 100%;height: 100%;top:0;left:0;bottom: 0;right: 0; display: flex;justify-content: center;flex-wrap: wrap;overflow: hidden; opacity:0.3;padding-top:10px";
div1.appendChild(div3);
}
//添加控制条
div1.appendChild(control);
}else{
var hasControlDiv=div1.querySelector("#"+divControlId);
if(hasControlDiv){
box.appendChild(hasControlDiv);
}
if($this.watermark){
var markDiv=div1.querySelector("#"+divId);
if(markDiv){
div1.removeChild(markDiv);
}
}
}
},200);
this.$emit('fullscreenchange',e);
//this.fullScreenFlag ? this.videoContext.exitFullScreen() : this.videoContext.requestFullScreen();
// this.fullScreenFlag ? this.bool=true : this.bool=false;
//this.fullScreenFlag=!this.fullScreenFlag;
},
error(e){
console.log(e,'播放错误');
this.$emit('error',e);
},
onTouchend(e){
if(this.contrlShowTimeout!=null){
window.clearTimeout(this.contrlShowTimeout);
}
if(!this.fullScreenFlag){
this.contrlShow=!this.contrlShow;
}else{
if(!this.contrlShow){
this.contrlShow=show;
}
}
// this.onPlayerPause()
// this.touchNum ++
// let $this=this;
// setTimeout(()=>{
// if($this.touchNum == 1){
// // console.log('单击')
// }else if($this.touchNum >= 2){
// if($this.playing){
// $this.onPause()
// } else {
// $this.onPlay()
// }
// }
// this.touchNum = 0
// },250)
},
onLoad(e){
this.contrlShow=false;
this.$emit('loadeddata',e);
},
onMetaLoad(e){
this.curVideo.duration=Number(e.detail.duration);
this.druationTime = this.formatSeconds(this.curVideo.duration);
this.contrlShow=true;
this.$emit('loadedmetadata',e);
},
onControlsToggle(e){
console.log(e,"ControlsToggle");
},
// 开始
onPlay(){
this.videoContext.play();
this.playing=true;
let $this=this;
if(this.contrlShow){
this.contrlShowTimeout=window.setTimeout(function(){
$this.contrlShow=false;
},5000);
}
this.$emit('play')
},
onTimeUpdate(e){
this.videoUpdate(e);
this.$emit('timeupdate',e)
},
onPause() {
this.playing=false;
this.$emit('pause')
},
onEnded(){
this.playing=false;
this.$emit('ended')
}
}
}
</script>
<style lang="scss" scoped>
.video-box{
width: 100%;
height: 100%;
position: relative;
}
.screen{
position: relative;
}
.screen-full{
position:static;
}
.process-container{
width:100%;
padding:1% 2% 1% 2%;
height:60rpx;
max-height:60rpx;
position:absolute;
bottom:0rpx;
color:#ffffff;
left:0;
right:0;
z-index:9999;
display:flex;
align-items: center;
background:rgba(59, 57, 57, 0.2);
}
.process-container image{
max-width:30rpx;
max-height:30rpx;
text-align:center;
}
.slider-container{
z-index:13;
height:60rpx;
margin-bottom:10rpx;
flex:6;
max-width:50%;
}
.controller-play{
width: 8%;
}
.controller-screen{
width: 10%;
}
.currtime{
color: #ffffff;
font-size: 22rpx;
width: 11%;
height: 100%;
line-height: 60rpx;
text-align: center;
}
.druationTime{
color: #ffffff;
font-size: 22rpx;
width: 12%;
height: 100%;
line-height: 60rpx;
text-align: center;
}
.player-speed{
position: relative;
color: #e5e5e5;
padding: 0 0.4rem;
transition: color 0.3s;
height: 22px;
}
.btn-speed:hover .speed-control {
// visibility: visible;
}
.speed-control {
position: absolute;
//top: 180px;
transition: visibility 0.3s;
transform: translate(-50%, -100%);
}
.speed-control .speed-control-list {
list-style: none;
color: #e5e5e5;
width: 50px;
font-size: 12px;
text-align: left;
padding: 0px 0px 0px 5px;
margin: 0;
overflow: hidden;
border-radius: 4px;
background: rgba(21, 21, 21, 0.8);
}
.speed-control .speed-control-list .li {
position: relative;
display: block;
height: 25px;
line-height: 25px;
}
.speed-control .speed-control-list .li:hover {
color: #fff;
background: rgba(99, 99, 99, 0.8);
}
.speed-control .speed-control-list .li.current {
color: var(--primaryColor);
}
</style>