做了一个涉及音视频的h5页面,做下问题记录

项目简介:h5页面内嵌到原生app中,可以分享(调app原生方法)到微信、朋友圈、qq、qq空间、微博,也可以用任何浏览器打开(不考虑pc)。

1.audio标签在ios上不会预加载,所以音频时长一开始获取不到,搜到一些偏门的方法(body.click一下;audio.play再马上audio.pause;)等,都不好使(可能是特殊情况能用,不建议用)。如果能后台返回时长就让后台返回一下,如果不行就让产品经理妥协吧。

2.用slider做自定义播放器,拖动进度条,更新audio当前时长,松手后进度条会弹回去导致无法拖动到指定位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 框架是vant-ui,进度条控件
<van-slider button-size="18px" class="vs" active-color="#2fb5ba" v-model="value" @change="changeProcess" @touchstart.native="isChange=true" @touchend.native="isChange=false" />

// 监听音频播放时间并更新进度条控件
dom.addEventListener('timeupdate', function () {
_this.updateProgress(dom);
}, false);

// ***拖动的时候鼠标还没松开达到赋值给当前时长前,audio的timeupdata方法就再次触发了,这时再松开鼠标,slider到指定进度,由于updateProgress在执行,可能change后又赋值value,导致change方法里面赋值时这个参数e可能不是松开鼠标的位置,而是audio的timeupdate方法赋值给当前时长的进度值,所以在松开鼠标前不要在updateProgress里给进度条value赋值,所以加了个isChange做开关
updateProgress(dom) {
this.currentTime = dom.currentTime
if(this.isChange) return
// 更新进度的逻辑就不多写了,没出问题
var value = dom.currentTime / this.duration || 0;
this.$set(this, 'value', parseInt(value * 100))
}

// 改变进度
changeProcess(e) {
let dom = document.getElementById('audio')
dom.currentTime = this.duration * (e/100)
if(this.isIOS) {
if(this.n > 0) {
this.play()
}
}else {
this.play()
}
}

3.自定义播放器有个需求,如果一开始未播放,直接拖动进度条,要自动播放,播放按钮变为暂停按钮。对安卓正常,对ios,由于一开始没有加载音频,在拖动进度条后的方法里触发play失败(在click中触发play就可以,可能是ios检测用户手势比较严吧),但是在play()方法中我把播放按钮变为了暂停按钮,导致视觉bug,所以加了个计数器n,播放一次后n++,大于0的时候在改变进度的时候再播放(代码在第二条的代码第23行上下)

4.video标签视频全屏播放及退出全屏问题(需求是点击视频自动全屏播放)。

ios上的video标签播放视频会自动全屏,上边也没发现下载按钮,看了几个苹果手机和ios12及以上版本效果都是一致的。

安卓则需要手动实现全屏:给单独的video标签赋视频链接并调用requestFullscreen()方法全屏(类似f11键)(看了西瓜视频的xgplayer web播放器中也是用的这个方法,心里有了底)。

但问题来了:在三星s9+和荣耀的一款机型上,全屏后点击系统返回键或屏幕返回手势都能退出全屏,留在当前页,但是oppo的手机用屏幕返回手势(还没有返回按键)就直接返回到上一页了

(猜测:各手机厂商针对安卓系统做的ui开发如miui,emui等,会对安卓交互做些调整,安卓本身返回就是返回上一页,只是三星oneui和荣耀系统加了些人性化的判断,如果有webkitfullscreenchange等会加个返回拦截)。

本来以为用户探索一下就可以了(全屏后也有退出全屏按钮),但产品经理不妥协,只能想偏方了 - 跳槽,哦不,跳转页面,返回时记录状态(keep-alive + 自行判断)。跳转到新页面全屏播video,这个video用的西瓜视频的web播放器xgplayer,全屏后点返回就返回上一页了(这个控件三星s9和荣耀也是返回上一页了,不细究了,那么多安卓手机也究不完啊,作为前端也不想在这上面浪费时间,想做更有意义的事)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
mounted() {
// 监听全屏
let dom = document.querySelector('#video')
dom.addEventListener("webkitfullscreenchange", function(e) {
let isFullScreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
if (isFullScreen) {
// 进入全屏
this.isFullScreen = true
} else {
// 退出全屏
this.isFullScreen = false
dom.pause()
dom.style.display = 'none'
dom.setAttribute('src', '')
}
})
},
1
2
3
4
5
6
7
8
9
10
11
12
// 全屏
toFullVideo(videoDom){
if(videoDom.requestFullscreen){
return videoDom.requestFullscreen();
}else if(videoDom.webkitRequestFullScreen){
return videoDom.webkitRequestFullScreen();
}else if(videoDom.mozRequestFullScreen){
return videoDom.mozRequestFullScreen();
}else{
return videoDom.msRequestFullscreen();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 跳转后的页面执行下这个方法,在mounted里
play() {
const player = new Player({
el: document.querySelector('#vs'),
url: url,
fluid: true,
rotateFullscreen: true,
autoplay: true,
closeVideoTouch: false,
})
setTimeout(() => {
let dom = document.querySelector('.xgplayer-fullscreen')
dom.click()
}, 50);
}

5.由于video标签在不同设备不同浏览器上的样式表现不同,默认样式得不到产品经理的认可,所以统一给video上边放一层元素,作为封面图,点击封面图进行视频播放。安卓的播放在第4条中写了。下面是ios中遇到的问题。ios中原生h5的video标签不会进行preload,封面是黑屏,点击原生标签的controls中的播放按钮,按钮会有个loading效果,但如果为了样式在video上放一个封面图,那video的加载效果就没了,如果视频很大,点击封面图后会等很长时间才播放,会让用户觉得是未响应,所以要有个loading效果