mirror of
https://codeup.aliyun.com/67762337eccfc218f6110e0e/vue/learning-system-mobile.git
synced 2025-12-07 01:46:44 +08:00
417 lines
11 KiB
Vue
417 lines
11 KiB
Vue
<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>
|