参考链接:
全屏旋转 https://blog.csdn.net/nidunlove/article/details/51944527
ios进度条滑动方向判断 https://www.cnblogs.com/yiyi17/p/7687273.html
项目基于vue-cli3+vant ui,使用cordova打包成app
1. 无可避免的在浏览器被X5内核劫持视频(微信浏览器,手机qq浏览器等):
就算自己写了标题栏和控制条,也会变成被劫持的样式,并在webview最顶层显示,就算是dailog/弹出层等都不能在视频上方显示,会被覆盖遮挡,此bug无解,并且时有时没有,有解请留言帮助。
2. 在被劫持后重复点击被劫持后的全屏按钮,会出现横屏不能变成竖屏的情况,小心操作即可,没办法就暴力退出软件,唉。
3. ios 打包app后全屏横屏后,本文使用的手势滑动拉取进度的体验感并不好,可能是我计算的比较粗糙。可以选择其他方式去模拟拉取进度条。
包裹视频大盒子为红框video-box,因为自己写了头部标题栏&控制条栏,并且全屏也需要显示,所以里面包含三部分:
1. van-nav-bar 头部标题栏部分
2. video 视频盒子video标签
3. video_control 控制条栏
先附上data代码
data() {
return {
title: '', // 视频标题
isPlay: false, // 是否在播放
isFullscreen: false, // 是否全屏
//视频
initVideo: {
play: false,//播放还是暂停 true播放中
videoLength: 3600,//时长
url: "",//视频课件Url
currentTime: 0,//当前播放时间
},
isShowControl: true, // 是否显示标题栏
isMove: false, //是否显示视频进度箱
isIphone: false, //是否ios设备
}
},
1.van-nav-bar 头部标题栏部分
isFullscreen 是否全屏状态,全屏/非全屏时显示不同的van-nav-bar高度样式等
这边用v-if=‘isFullscreen’控制,你们也可以使用类名控制
<!-- 非全屏状态van-nav-bar -->
<van-nav-bar :title="title" left-arrow @click-left="goBack" class="title" v-show='isShowControl' v-if='!isFullscreen'>
<div slot="right">
<!-- 收藏/非收藏 -->
<van-icon name="star-o" v-if='isCollected==0' @click="addCollectCourse" />
<van-icon name="star" v-else color='#fff' @click="delCollectCourse" />
<!-- 分享按钮 -->
<img v-if="isApp" class="btn-share" src="../../assets/img/home-details-share-blank.png" @click="showShareSheet=true" />
</div>
</van-nav-bar>
<!-- 全屏状态van-nav-bar -->
<van-nav-bar :title="title" left-arrow @click-left="goBack" class="title-full" v-show='isShowControl' v-if='isFullscreen'>
<div slot="right">
<van-icon name="star-o" v-if='isCollected==0' @click="addCollectCourse" />
<van-icon name="star" v-else color='#fff' @click="delCollectCourse" />
<img v-if="isApp" class="btn-share" src="../../assets/img/home-details-share-blank.png" @click="fullShare" />
</div>
</van-nav-bar>
2.video 视频盒子video标签
特别注意:打包成app的时候 需要在打包设置里面设置以下
webview.allowsInlineMediaPlayback=YES,这样才可以实现ios app中内联播放,否则一点击视频就进入ios的全屏层
代码
<!-- video API相关获取与调用 -->
<video class="video" ref="video" webkit-playsinline playsinline x5-playsinline="" :src="initVideo.url" @pause="handPlay(2,2)" @play="handPlay(2,1)" @loadedmetadata="getAudioLength(2)" @timeupdate="videoTimeUpdate" @click="clickVideo" v-if='initVideo.url' poster="../../assets/img/video-default-pictures.png">
该浏览器不支持video
</video>
3.video_control 控制条栏
isFullscreen 也是分为了全屏/非全屏状态
另外isFullscreen 全屏状态下,又分isIphone控制是ios的全屏还是安卓的全屏。因为本人解决ios全屏的方法,ios全屏状态下进度条不能使用,所以ios全屏状态下禁用进度条并增加滑动进度箱
<!-- 非全屏状态video_control -->
<div class="video_control" data-way='0' v-show='isShowControl' v-if='!isFullscreen'>
<div class="progress">
<!-- 播放按钮 -->
<van-icon v-if='!initVideo.play' name="play" color='#fff' class="icon-play" @click.native="playVideo" />
<!-- 暂停 -->
<van-icon v-else name="pause" color='#fff' class="icon-play" @click.native="playVideo" />
<!-- 当前播放时间 -->
<span class="time-num">{{initVideo.currentTime | videoTime}}</span>
<!-- 进度条 -->
<van-slider v-model="initVideo.currentTime" :step='0.01' @change="changeVideoTime" :max='initVideo.videoLength' class="percentage" />
<!-- videoLength 总时间,currentTime 当前时间,videoTime 自定义过滤器 -->
<span class="time-num">{{initVideo.videoLength | videoTime}}</span>
<!-- 非全屏状态下全屏按钮-->
<img class="fullscreen" src="../../assets/img/quanpin.png" alt="" @click="full">
</div>
</div>
<!-- 全屏状态video_control-full 安卓设备 -->
<div class="video_control-full" data-way='0' v-show='isShowControl&&!isIphone' v-if='isFullscreen'>
<div class="progress">
<van-icon v-if='!initVideo.play' name="play" color='#fff' class="icon-play" @click.native="playVideo" />
<van-icon v-else name="pause" color='#fff' class="icon-play" @click.native="playVideo" />
<span class="time-num">{{initVideo.currentTime | videoTime}}</span>
<van-slider v-model="initVideo.currentTime" :step='0.01' @change="changeVideoTime" :max='initVideo.videoLength' class="percentage" />
<span class="time-num">{{initVideo.videoLength | videoTime}}</span>
<img class="fullscreen" src="../../assets/img/quanpin.png" alt="" @click="full">
</div>
</div>
<!-- 全屏状态video_control-full ios设备 -->
<div class="video_control-full" data-way='0' v-show='isShowControl&&isIphone' v-if='isFullscreen'>
<div class="progress">
<van-icon v-if='!initVideo.play' name="play" color='#fff' class="icon-play" @click.native="playVideo" />
<van-icon v-else name="pause" color='#fff' class="icon-play" @click.native="playVideo" />
<span class="time-num">{{initVideo.currentTime | videoTime}}</span>
<!-- 进度条 禁用滑动 -->
<van-slider v-model="initVideo.currentTime" :step='0.01' @change="changeVideoTime" :max='initVideo.videoLength' :disabled='true' class="percentage" />
<span class="time-num">{{initVideo.videoLength | videoTime}}</span>
<img class="fullscreen" src="../../assets/img/quanpin.png" alt="" @click="full">
</div>
</div>
<!-- 全屏状态 ios设备增加的视频进度箱forward-box -->
<div class="forward-box" v-show='isFullscreen&&isIphone' v-if='isMove'>
<span>{{initVideo.currentTime | videoTime}}/{{initVideo.videoLength|videoTime}}</span>
</div>
全部html代码
<div class="course-detail">
<!-- 包裹视频的大盒子video-box-->
<div class="video-box">
<!-- 非全屏状态van-nav-bar -->
<van-nav-bar :title="title" left-arrow @click-left="goBack" class="title" v-show='isShowControl' v-if='!isFullscreen'>
<div slot="right">
<!-- 收藏/非收藏 -->
<van-icon name="star-o" v-if='isCollected==0' @click="addCollectCourse" />
<van-icon name="star" v-else color='#fff' @click="delCollectCourse" />
<!-- 分享按钮 -->
<img v-if="isApp" class="btn-share" src="../../assets/img/home-details-share-blank.png" @click="showShareSheet=true" />
</div>
</van-nav-bar>
<!-- 全屏状态van-nav-bar -->
<van-nav-bar :title="title" left-arrow @click-left="goBack" class="title-full" v-show='isShowControl' v-if='isFullscreen'>
<div slot="right">
<van-icon name="star-o" v-if='isCollected==0' @click="addCollectCourse" />
<van-icon name="star" v-else color='#fff' @click="delCollectCourse" />
<img v-if="isApp" class="btn-share" src="../../assets/img/home-details-share-blank.png" @click="fullShare" />
</div>
</van-nav-bar>
<!-- video API相关获取与调用 -->
<video class="video" ref="video" webkit-playsinline playsinline x5-playsinline="" :src="initVideo.url" @pause="handPlay(2,2)" @play="handPlay(2,1)" @loadedmetadata="getAudioLength(2)" @timeupdate="videoTimeUpdate" @click="clickVideo" v-if='initVideo.url' poster="../../assets/img/video-default-pictures.png">
该浏览器不支持video
</video>
<!-- 非全屏状态video_control -->
<div class="video_control" data-way='0' v-show='isShowControl' v-if='!isFullscreen'>
<div class="progress">
<!-- 播放按钮 -->
<van-icon v-if='!initVideo.play' name="play" color='#fff' class="icon-play" @click.native="playVideo" />
<!-- 暂停 -->
<van-icon v-else name="pause" color='#fff' class="icon-play" @click.native="playVideo" />
<!-- 当前播放时间 -->
<span class="time-num">{{initVideo.currentTime | videoTime}}</span>
<!-- 进度条 -->
<van-slider v-model="initVideo.currentTime" :step='0.01' @change="changeVideoTime" :max='initVideo.videoLength' class="percentage" />
<!-- videoLength 总时间,currentTime 当前时间,videoTime 自定义过滤器 -->
<span class="time-num">{{initVideo.videoLength | videoTime}}</span>
<!-- 非全屏状态下全屏按钮-->
<img class="fullscreen" src="../../assets/img/quanpin.png" alt="" @click="full">
</div>
</div>
<!-- 全屏状态video_control-full 安卓设备 -->
<div class="video_control-full" data-way='0' v-show='isShowControl&&!isIphone' v-if='isFullscreen'>
<div class="progress">
<van-icon v-if='!initVideo.play' name="play" color='#fff' class="icon-play" @click.native="playVideo" />
<van-icon v-else name="pause" color='#fff' class="icon-play" @click.native="playVideo" />
<span class="time-num">{{initVideo.currentTime | videoTime}}</span>
<van-slider v-model="initVideo.currentTime" :step='0.01' @change="changeVideoTime" :max='initVideo.videoLength' class="percentage" />
<span class="time-num">{{initVideo.videoLength | videoTime}}</span>
<img class="fullscreen" src="../../assets/img/quanpin.png" alt="" @click="full">
</div>
</div>
<!-- 全屏状态video_control-full ios设备 -->
<div class="video_control-full" data-way='0' v-show='isShowControl&&isIphone' v-if='isFullscreen'>
<div class="progress">
<van-icon v-if='!initVideo.play' name="play" color='#fff' class="icon-play" @click.native="playVideo" />
<van-icon v-else name="pause" color='#fff' class="icon-play" @click.native="playVideo" />
<span class="time-num">{{initVideo.currentTime | videoTime}}</span>
<!-- 进度条 禁用滑动 -->
<van-slider v-model="initVideo.currentTime" :step='0.01' @change="changeVideoTime" :max='initVideo.videoLength' :disabled='true' class="percentage" />
<span class="time-num">{{initVideo.videoLength | videoTime}}</span>
<img class="fullscreen" src="../../assets/img/quanpin.png" alt="" @click="full">
</div>
</div>
<!-- 全屏状态 ios设备增加的视频进度箱forward-box -->
<div class="forward-box" v-show='isFullscreen&&isIphone' v-if='isMove'>
<span>{{initVideo.currentTime | videoTime}}/{{initVideo.videoLength|videoTime}}</span>
</div>
</div>
<van-tabs class="tab-bar"> tab栏 </van-tabs>
</div>
css样式
.course-detail {
height: 100vh;
width: 100%;
overflow: hidden;
display: flex;
flex-direction: column;
.video-box {
width: 100%;
height: 216px;
background: #eeeeee;
position: relative;
overflow: hidden;
.video {
width: 100%;
height: 100%;
position: absolute;
// position: relative;
left: 0;
top: 0;
}
.forward-box {
position: absolute;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
width: 100px;
height: 50px;
background-color: rgba(0, 0, 0, 0.3);
display: flex;
justify-content: center;
align-items: center;
color: #e9e8e8;
}
img {
width: 100%;
height: 100%;
}
.van-nav-bar {
background-color: rgba(0, 0, 0, 0.3);
height: 40px;
line-height: 40px;
width: 100%;
position: absolute;
z-index: 9999999999999;
.van-icon {
color: #fff;
font-size: 16px;
}
.van-nav-bar__title {
color: #fff;
font-size: 16px;
}
.van-nav-bar__text {
color: #fff;
font-size: 14px;
}
.van-nav-bar__right {
.van-icon-cart-o {
font-size: 20px;
}
.van-icon-ellipsis {
font-size: 20px;
margin-left: 20px;
transform: rotateZ(90deg);
}
}
&[class*="van-hairline"]:after {
border-color: transparent;
}
}
}
.video_control {
position: absolute;
height: 40px;
// top: 240px;
left: 0;
bottom: 0;
width: 100%;
z-index: 555 !important;
.progress {
height: 100%;
padding: 0 5px;
background-color: rgba(0, 0, 0, 0.3);
display: flex;
align-items: center;
justify-content: space-between;
}
.percentage {
margin-left: 5px;
margin-right: 5px;
width: 55%;
// flex: 1;
}
.time-num {
color: #fff;
}
.icon-play {
width: 25px;
height: 25px;
font-size: 25px;
}
.fullscreen {
width: 20px;
height: 20px;
margin-left: 5px;
}
}
.video_control-full {
position: absolute;
height: 30px;
left: 0;
bottom: 0;
width: 100%;
z-index: 9999999999999999 !important;
transform: translate3d(0%, 0%, 0);
.progress {
height: 100%;
padding: 0 8px;
background-color: rgba(0, 0, 0, 0.3);
display: flex;
align-items: center;
justify-content: space-between;
}
.time-num {
font-size: 10px;
color: #fff;
}
.percentage {
margin-left: 2px;
margin-right: 2px;
width: 55%;
// flex: 1;
}
.icon-play {
width: 15px;
height: 15px;
font-size: 15px;
}
.fullscreen {
width: 15px;
height: 15px;
margin-left: 5px;
}
@{deep} .van-slider__button {
width: 10px;
height: 10px;
}
@{deep} .van-slider--disabled {
opacity: 1 !important;
}
}
.tab-bar {
flex: 1;
z-index: 1;
overflow: hidden;
display: flex;
flex-direction: column;
}
}
苹果ios下手势滑动屏幕更改视频的播放进度,本人项目在安卓端使用vant UI里面的Slider进度条。
安卓端横屏全屏后手势依然可以使用,所以直接滑动Slider控制播放进度。
由于ios端方向&手势问题,全屏后设置slider不可滑动(disabled),利用一下手势代码控制视频的currentTime,以达到进度控制,并显示在视频进度箱中。
mounted的时候调用以下代码
// mounted的时候调用以下代码
const that = this
//mounted判断是否时ios 才进行以下监听滑动的代码
if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) {
console.log('苹果设备');
this.isIphone = true
//视频大盒子
let fullBox = document.querySelector('.video-box')
//监听手指接触视频大盒子屏幕事件touchstart touchmove touchend
fullBox.addEventListener("touchstart", function (e) {
startx = e.touches[0].pageX;
starty = e.touches[0].pageY;
curLength = that.initVideo.currentTime
}, false);
fullBox.addEventListener("touchmove", function (e) {
var movex, movey
movex = e.touches[0].pageX;
movey = e.touches[0].pageY;
// 全屏时
if (that.isFullscreen) {
// isMove 滑动中显示视频进度箱
that.isMove = true
if (that.$refs.video) {
// 滑动时暂停
that.$refs.video.pause()
}
//isTouchMove 作为滑动结束时是否播放视频的标志
isTouchMove = true
}
var direction = getDirection(startx, starty, movex, movey);
switch (direction) {
case 0:
console.log("未滑动!");
break;
case 1:
if (that.isFullscreen) {
console.log("向上!")
let changelength = movey - starty
console.log(changelength, 'changelength');
that.initVideo.currentTime = curLength + parseInt(changelength)
if (that.initVideo.currentTime <= 0) {
that.initVideo.currentTime = 0
}
if (that.initVideo.currentTime > that.initVideo.videoLength) {
that.initVideo.currentTime = that.initVideo.videoLength - 5
}
}
break;
case 2:
if (that.isFullscreen) {
console.log("向下!")
let changelength = movey - starty
console.log(changelength, 'changelength');
that.initVideo.currentTime = curLength + parseInt(changelength)
if (that.initVideo.currentTime <= 0) {
that.initVideo.currentTime = 0
}
if (that.initVideo.currentTime > that.initVideo.videoLength) {
that.initVideo.currentTime = that.initVideo.videoLength - 5
}
}
break;
case 3:
console.log("向左!")
break;
case 4:
console.log("向右!")
break;
default:
}
}, false);
//手指离开屏幕
fullBox.addEventListener("touchend", function (e) {
var endx, endy;
endx = e.changedTouches[0].pageX;
endy = e.changedTouches[0].pageY;
var direction = getDirection(startx, starty, endx, endy);
if (that.isFullscreen) {
that.isMove = false
if (isTouchMove) {
if (that.$refs.video) {
that.$refs.video.play()
}
isTouchMove = false
}
}
switch (direction) {
case 0:
console.log("未滑动!");
break;
case 1:
if (that.isFullscreen) {
console.log("向上!")
if (that.$refs.video) {
that.$refs.video.currentTime = that.initVideo.currentTime;
}
}
break;
case 2:
if (that.isFullscreen) {
console.log("向下!")
if (that.$refs.video) {
that.$refs.video.currentTime = that.initVideo.currentTime;
}
}
break;
case 3:
console.log("向左!")
break;
case 4:
console.log("向右!")
break;
default:
}
}, false);
}
点击全屏按钮,调用full()方法
full() {
// 当不是全屏的时候
if (!this.isFullscreen) {
if (!this.isPlay) {
if (this.$refs.video) {
//这里每次全屏之后将视频播放
this.$refs.video.play()
}
}
setTimeout(() => {
//设置进入全屏的各种方法,一般安卓app会进入全屏但不会横屏(横屏方法在下面,要使用cordova插件),ios会进入else
var ele = document.querySelector('.video-box')
if (ele.requestFullscreen) {
ele.requestFullscreen()
} else if (ele.mozRequestFullScreen) {
ele.mozRequestFullScreen()
} else if (ele.webkitRequestFullScreen) {
//安卓微信
ele.webkitRequestFullScreen()
} else {
console.log('想要进入全屏但进入了else');
if (this.isIphone) {
console.log('苹果设备')
//ios调用horizontalScreen方法, 强制全屏横屏
horizontalScreen('.video-box')
}
}
// ios 强制全屏横屏函数horizontalScreen
function horizontalScreen(className) {
// transform 强制横屏
var conW = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
var conH = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
document.querySelector(className).style.transform = "rotate(90deg) translate(" + ((conH - conW) / 2) + "px," + ((conH - conW) / 2) + "px)"
document.querySelector(className).style.width = conH + "px"
document.querySelector(className).style.height = conW + "px"
document.querySelector(className).style.transformOrigin = "center center"
document.querySelector(className).style.webkitTransformOrigin = "center center"
document.querySelector(className).style.zIndex = '999999999999'
document.querySelector(className).style.position = 'absolute'
if (document.querySelector(".video")) {
document.querySelector(".video").style.zIndex = ''
document.querySelector(".video").style.position = 'relatived !important'
}
var max = conW > conH ? conW : conH;
var min = conW > conH ? conH : conW;
//重新设置.video-box宽高
document.querySelector(className).style.width = max + "px";
document.querySelector(className).style.height = min + "px";
}
//安卓app横屏
if (!this.isIphone) {
//cordova-plugin-screen-orientation插件的方法,用于在安卓app全屏时设置变成横屏
screen.orientation.lock('landscape')
}
this.isFullscreen = true
setTimeout(() => {
if (this.$refs.video) {
//这里每次全屏横屏之后将视频播放
this.$refs.video.play()
}
}, 0);
}, 100);
} else {
//设置退出全屏的各种方法,一般安卓会退出全屏但不会恢复竖屏,ios会进入else
if (document.cancelFullScreen) {
console.log('document.cancelFullScreen()');
document.cancelFullScreen();
} else if (document.mozCancelFullScreen) {
console.log('document.mozCancelFullScreen()');
document.mozCancelFullScreen();
} else if (document.webkitCancelFullScreen) {
console.log('document.webkitCancelFullScreen()');
//安卓微信
document.webkitCancelFullScreen();
} else if (document.webkitExitFullScreen) {
console.log('document.webkitExitFullScreen()');
document.webkitExitFullScreen()
} else {
console.log('想要退出全屏但进入了else');
if (this.isIphone) {
console.log('苹果设备');
// 设置css恢复为原本的css
var docHtml = document.documentElement;
var docBody = document.body;
var videobox = document.querySelector('.video-box');
docHtml.style.cssText = "";
docBody.style.cssText = "";
videobox.style.cssText = "";
}
}
// 安卓app退出横屏
if (!this.isIphone) {
//cordova-plugin-screen-orientation插件的方法,用于在安卓app退出全屏时设置不锁定为横屏,即变为竖屏
screen.orientation.unlock()
}
this.isFullscreen = false
setTimeout(() => {
if (this.$refs.video) {
//这里每次退出全屏之后将视频播放
this.$refs.video.play()
}
}, 500);
}
},