在座的傻 x
本喵来了
今天写的文章一(亿)级棒!
没错,今天要说的对象就是“网页播放器”这个逼,这玩意看起来没什么难度,但实际上有几个坑,下面由本帅气无敌喵逐一解说如何解决在开发中可能会遇到的坑。
- 无法自动播放
- 全屏问题
- 手机端播放器自定义控制条无法显示
01无法自动播放
不就是 video 标签添加一个 autoplay 吗?很遗憾...事情并没有这么简单。
桌面版的 Safari 在 2017 年的 11 版开始禁止了带有声音的视频自动播放,2018 年 4 月份发布的 Chrome 66 也禁止了,随后各个浏览器都跟随着苹果和谷歌两位大佬的脚本逐一禁止了。
请注意,是禁止带有声音的网页视频自动播放,因此,自动播放和声音是有奸情!!!
想要自动播放可以通过以下几种方式解决。
- video 标签添加一个 muted 属性(静音)
静音的视频是允许自动播放。
- 用户在网站上进行了互动
这个办法在字面上可能很难理解,举个栗子吧。
杰瑞鼠打开了浏览器,访问了黄网“TOM and JERRY”的首页(带有视频),在首页点击某个黄涩视频链接,进入到了这个视频详情。
那么假设首页和这个视频详情的 video 都有 autoplay 这个属性,没有 muted 属性,请问这两个视频是否在网页加载的那一刻起能够自动播放吗?
答案是:首页的 video 不能自动播放,但是视频详情里的 video 可以播放(且有声音),因为在同一个会话里,在进入视频详情前,用户已经打开了同站点下的首页,也就是说,用户已经与网站进行了交互,而用户刚进入首页前,是没有访问过同站点下的其他网页,也即是没有任何交互,因此首页的 video 不能自动播放。
- 浏览器设置“允许自动播放”
这种方法就是全面开放自动播放功能,没有“静音”和“交互”的限制了,需要用户自行设置。以 chome 浏览器为例,在地址栏访问 chrome://flags/,搜索“Autoplay”,即可搜索到该设置(不过,高版本的 chrome 已经不是在这里设置了,本喵也找不到设置的地方)。
再以火狐浏览器为例,在选项里找“自动播放”,即可找到。
- 浏览器域名白名单(未证实)
听说浏览器有个域名白名单的东西,只要将域名填入该白名单,访问相关网站就可以自动播放,但目前为止本喵手上没有足够证据证实各个大厂的 py 交易。
上述几种自动播放解决方法各有缺点,为了让用户体验好一点,有时候,我们需要检测网页打开时是否支持自动播放,若不支持,则在视频中间显示播放按钮或者出现其他的样式,下面贴一下检测自动播放代码。
var promise = document.querySelector('video').play()
if (promise !== undefined) {
promise.then(() => {
// 支持自动播放且有声音
}).catch(error => {
// 不支持自动播放且有声音,这个时候可以在视频上面显示一个播放图标,提示用户自己点击播放
})
}
但不是所有的浏览器的 video.play() 都支持返回 promise。想了解更多,可以到这个网站看看。
https://developer.mozilla.org...
02 全屏问题
废话不说,先贴代码。
<!-- 这里专门用一个 div 包含 video,这样做是有原因的,下面有说明 -->
<div class="video-box">
<video src="xxx" poster=""></video>
</div>
<script>
// 检测是否全屏(IOS 端无效)
function checkFullScreen() {
var isFull = document.webkitIsFullScreen || document.mozFullScreen ||
document.msFullscreenElement || document.fullscreenElement
if (isFull == null || isFull == undefined) {
isFull = false
}
return isFull
}
// 全屏
function toggleFullScreen() {
var videoBox = document.querySelector('.video-box')
// video 是 video-player 里面的 video 标签,这个用于 ios 端全屏
var video = document.querySelector('.video-box video')
var isFull = checkFullScreen()
//W3C
if (videoBox.requestFullscreen) {
isFull ? document.exitFullscreen() : videoBox.requestFullscreen()
}
//FireFox
else if (videoBox.mozRequestFullScreen) {
isFull ? document.mozCancelFullScreen() : videoBox.mozRequestFullScreen()
}
//Chrome
else if (videoBox.webkitRequestFullScreen) {
isFull ? document.webkitCancelFullScreen() : videoBox.webkitRequestFullScreen()
}
//IE11
else if (videoBox.msRequestFullscreen) {
isFull ? document.msExitFullscreen() : videoBox.msRequestFullscreen()
}
// IOS(特例)
else if (video.webkitEnterFullscreen) {
video.webkitEnterFullscreen()
}
// 这里可以做一些判断,更换缩放图标(对 IOS 端没效果)
if (isFull) {
} else {
}
}
</script>
上面的全屏代码适用于 pc(Windows和Mac)、移动端(安卓和IOS),主要使用到了 requestFullscreen API,该 API 适用于 PC 和安卓,但很遗憾,IOS 不适用,IOS 端就是个另类,只能用 webkitEnterFullscreen API 进入全屏,而且没有退出全屏的 API,进入全屏后,只能用 iphone 的手势或自带控件进行退出全屏。
如果你发现 requestFullscreen API 失效,以下网站有说明 requestFullscreen API 失效的原因。
https://stackoverflow.com/que...
But 事情没有这么简单,在开发过程中依旧会遇到很多问题,下面逐一说明。
- PC 端全屏后无法监听 ESC 键
在 PC 端里,有时候需要退出全屏后做一些操作,点击退出全屏按钮跑逻辑是没问题的,但是不要忘记,按 ESC 键也是退出全屏操作,也需要进行跑逻辑。而当元素使用了 requestFullscreen API 进行全屏时,不需要写任何代码,ESC 键就会默认用来退出全屏,我们自然会想到用 onkeydown 事件来监听 ESC,虽然 onkeydown 事件是可监听,但是唯独 ESC 键是无法监听。
document.onkeydown = function () {
if (event.keyCode == 27) {
// 退出全屏
}
}
也即是说,上面的代码,按 ESC 是不走的。那咋办?别担心,我们可以利用 onresize 曲线救国,当用户按下 ESC 时,全屏就会失效,windows 的宽高会变小,即会触发 onresize,这个时候再检测是不是非全屏情况,再跑逻辑。
window.onresize = function () {
if (!checkFullScreen()) {
// 按 esc 退出全屏需要执行的代码
}
}
- IOS端全屏无法自定义控制条
由于 IOS 端的全屏只能调用 webkitEnterFullscreen 将 video 标签进行全屏(其实就是 IOS 端内置的全屏,注意:是只能针对 video 标签全屏),全屏时是不能显示自定义的控制条。
But 我们可以用样式写一个“假全屏”的代码。
<script>
// 为了方便,下面用了 jq
// 判断是否是 IOS 端
var isIOS = !(navigator.userAgent.indexOf("Android") > -1) && (/Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent))
function toggleFullscreen() {
if ($('.video-box').hasClass('fullscreen')) {
// 这里设死高度 210 了,可以自己更改
$('.video-box').removeClass('fullscreen').removeClass('transform').width('100%').height(210).css('margin', '0')
} else {
$('.video-box').addClass('fullscreen')
if ($(window).width() < $(window).height() && isIOS) {
$('.video-box').width($(window).height()).height($(window).width()).css('margin', '-' + $(window).width() / 2 + 'px 0 0 -' + $(window).height() / 2 + 'px').addClass('transform')
} else {
$('.video-box').width($(window).width()).height($(window).height()).css('margin', '-' + $(window).height() / 2 + 'px 0 0 -' + $(window).width() / 2 + 'px')
}
}
}
// 重力感应,改变屏幕方向,如果是全屏时,也进行相应的改变
window.onresize = function () {
if ($('.video-box').hasClass('fullscreen')) {
if ($(window).width() < $(window).height() && isIOS) {
$('.video-box').width($(window).height()).height($(window).width()).css('margin', '-' + $(window).width() / 2 + 'px 0 0 -' + $(window).height() / 2 + 'px').addClass('transform')
} else {
$('.video-box').width($(window).width()).height($(window).height()).css('margin', '-' + $(window).height() / 2 + 'px 0 0 -' + $(window).width() / 2 + 'px').removeClass('transform')
}
}
}
</script>
<style>
/* 屏幕旋转的样式 */
.video-box.fullScreen.transform {
transform: rotate(90deg);
-ms-transform: rotate(90deg);
-webkit-transform: rotate(90deg);
-o-transform: rotate(90deg);
-moz-transform: rotate(90deg);
transform-origin: 50%;
-ms-transform-origin: 50%;
-webkit-transform-origin: 50%;
-moz-transform-origin: 50%;
-o-transform-origin: 50%;
}
/* 屏幕改变方向时,播放器控制条,需要固定 */
.video-box.fullScreen.transform .control {
position: fixed;
}
/* 全屏需要更改位置 */
.video-box.fullScreen {
position: fixed;
top: 50%;
left: 50%;
z-index: 10000;
}
</style>
上面的代码也兼容安卓端
不过这种方式存在一些体验问题,比如:使用重力感应横屏时,浏览器的地址栏会浮在上面,这个地址栏是无法去掉的。
- 视频全屏时也需要将控制条进行全屏
估计没有傻 x 产品会用播放器自带的丑陋控制条吧......既然我们要自定义控制条的样式,那就不会在 video 标签添加 controls 属性,而是在 video-box 的 div 下添加一个控制条相关的 div。
<div class="video-box">
<video src="xxx" poster=""></video>
<!-- 控制条 -->
<div class="ctrl-box"></div>
</div>
那么全屏时,我们不应该只考虑将 video 进行全屏,同时也要将控制条进行全屏,实现很简单,只要将 video-box 这个父类标签进行全屏即可。这也是为什么全屏代码里是将 video-box 进行全屏,而不是单独将 video 全屏,以及为什么要有个父类 div 包住 video。
- iframe 里面的元素全屏失败
如果 video 标签是在 iframe 里,iframe 必须声明允许全屏。
<iframe src="" allowfullscreen="allowfullscreen" mozallowfullscreen="mozallowfullscreen" msallowfullscreen="msallowfullscreen" oallowfullscreen="oallowfullscreen" webkitallowfullscreen="webkitallowfullscreen"></iframe>
03 手机端播放器自定义控制条无法显示
如今,手机端主要分为两大阵容:安卓和 IOS,在这两个端里,我们自定义的播放器控制条都会出现各种问题,下面一一列举。
- 安卓
在安卓端里,因为比较开放,浏览器可以说是百花齐放,有各种各样的功能,其中,有个对开发者不友好的情况就是某些浏览器(例如:QQ 浏览器)会去掉我们自定义的播放器控制条,改用浏览器内置的默认控制条。
解决方法如下:
...
...
...
无解!!!
先等等,别急着抓本喵猫尾。这个确实是无解的,有些浏览器厂商就是不愿意开发者可以自定义控制条,你可能会说为什么像虎牙直播这种大厂在手机上的 QQ 浏览器可以使用自定义控制条,那是因为......嗯......他们有 py 交易,没错,就是 py 交易!
例如:QQ 浏览器就有一个域名白名单的东西,而虎牙直播的域名就在这个白名单里,所以我们访问虎牙直播网站时,可以发现虎牙直播是可以显示自定义控制条。
不信?你试下在电脑使用 Fiddler 软件在本地做下代理,让手机和电脑连接同一个局域网,配置这个代理,然后再在电脑上做一下 hosts,将虎牙的域名映射到本地 IP,你就可以在手机里的 QQ 浏览器通过虎牙的域名访问到自己的网站,看看是不是自定义控制条显示出来了。
有关这个问题,本喵还特地在思否提问了。
https://segmentfault.com/q/10...
没错,就是无解,所以哪个傻 x 产品问你为什么这个功能无法实现,你就回答他,“你在教我做事?”
- IOS
大家都清楚 IOS 系统是封闭的,封闭到规定 IOS 端里的所有厂商的浏览器都不能支持 requestFullscreen API,只能支持独有的 webkitEnterFullscreen API,全屏时只能显示苹果的那一套控件,导致全屏是没任何办法显示自定义控制条的,不过在非全屏情况下,是可以显示自定义进度条,当然你也可以用上文那里的“假全屏”代码。
好了好了
这期干货就到这里了
本喵要捉杰瑞鼠了
溜了溜了