H5全屏API与视频全屏
背景
做web视频的同学基本上逃不掉使用全屏API。之前笔者做了web视频相关的工作,也遇到一些全屏的坑,本文简单总结一下。下图是文章大纲:
(上图使用笔者开发的web思维导图编辑)
原生 FullScreen API
Element.requestFullscreen()
用于将特定元素打开全屏。使用方式是先获取HTML Element元素,然后调用其 requestFullscreen
方法:
const buttomElem = document.getElementById('myButton');
buttomElem.addEventListener('click', function() {
const videoElem = document.getElementById("myVideo");
// 打开全屏
videoElem.requestFullscreen();
}, false);
注意:打开全屏只能通过用户操作触发,比如click事件。如果在一开始加载页面的时候调用 requestFullscreen
方法并不能打开全屏,且会在控制台中看到报错。
document.exitFullscreen()
用于退出全屏模式,与 requestFullscreen
不同,该方法挂载在document中:
const closeElem = document.getElementById('close');
closeElem.addEventListener('click', function() {
// 退出全屏
document.exitFullscreen();
}, false);
document.fullscreenElement
该属性表示当前全屏模式下的Element元素。如果这个值为null,则表示不处于全屏模式。使用这个属性可以判断当前页面是否处于全屏模式:
// 切换全屏和非全屏模式的按钮
const toggleElem = document.getElementById('toggle');
toggleElem.addEventListener('click', function() {
// 判断是否是全屏模式
if (document.fullscreenElement) {
// 退出全屏
document.exitFullscreen();
} else {
const videoElem = document.getElementById("myVideo");
// 打开全屏
videoElem.requestFullscreen();
}
}, false);
document.fullscreenEnabled
该属性表示当前浏览器是否是否支持全屏模式。
const buttomElem = document.getElementById('myButton');
buttomElem.addEventListener('click', function() {
if (document.fullscreenEnabled) {
alert('不支持全屏');
return;
}
// 这里放打开全屏的操作代码
}, false);
fullscreenchange事件
document
对象 和 Element
对象均可监听 fullscreenchange
事件。用于监听全屏模式的变化
document.addEventListener('fullscreenchange', function () {
if (document.fullscreenElement) {
console.log(`当前为打开全屏模式`);
} else {
console.log('当前为退出全屏模式');
}
});
Fullscreen API 的兼容问题
不同浏览器对Fullscreen的API使用方式并不一样。webkit、Firefox和IE需要添加给Fullscrren API添加特殊前缀才能使用,也有一些API名称不一样了,请看下面的表格:
标准 | webkit | Firefox | IE | |
---|---|---|---|---|
打开全屏 | requestFullscreen | webkitRequestFullscreen | mozRequestFullScreen | msRequestFullscreen |
退出全屏 | exitFullscreen | webkitExitFullscreen | mozCancelFullScreen | msExitFullscreen |
全屏元素 | fullscreenElement | webkitFullscreenElement | mozFullScreenElement | msFullscreenElement |
是否支持全屏 | fullscreenEnabled | webkitFullscreenEnabled | mozFullScreenEnabled | msFullscreenEnabled |
全屏变化事件 | fullscreenchange | webkitfullscreenchange | mozfullscreenchange | MSFullscreenChange |
全屏报错事件 | fullscreenerror | webkitfullscreenerror | mozfullscreenerror | MSFullscreenError |
如果要兼容所有的浏览器,需要判断不同的浏览器环境并使用对应的API。例如下面是一个兼容 requestFullscreen
的例子:
requestFullscreen.compatibility.js:
function requestFullscreen(element) {
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
}
}
exitFullscreen
、fullscreenElement
等其余的Fullscreen API也要做类似的兼容。这种兼容代码自己来写真的十分麻烦,这个时候可以求助于一个npm包:screenfull。
screenfull
screenfull的API兼容了所有浏览器的调用方式,且API使用起来更加简洁。上面requestFullscreen.compatibility.js的例子,用了screenfull后只需寥寥几行代码:
import screenfull from 'screenfull';
function requestFullscreen(element) {
screenfull.request(element);
}
下面是原生 Fullscreen API与 screenfull
API的对应关系:
import screenfull from 'screenfull';
// 打开全屏
function requestFullscreen(element) {
screenfull.request(element);
}
// 退出全屏
function exitFullscreen() {
screenfull.exit();
}
// 获取全屏模式下的元素
function fullscreenElement() {
return screenfull.element;
}
// 获取浏览器是否支持全屏模式
function fullscreenEnabled() {
return screenfull.isEnabled;
}
// 监听全屏事件
function onfullscreenchange(callback) {
screenfull.on('change', () => {
// screenfull.isFullscreen用于判断当前是否全屏
callback(screenfull.isFullscreen);
});
}
IOS视频全屏
我们先看看原生 Fullscreen API 的兼容表:
嗯,挺多绿的。但是细心观察的话会发现有个“刺头”:
对,我们亲爱的IOS系统并不支持原生 Fullscreen API。IOS只能对video元素全屏,其他HTML元素都不能全屏,而且IOS的全屏API是独有的API:
VideoElement.webkitEnterFullscreen
:打开video全屏VideoElement.webkitDisplayingFullscreen
:判断是否video的全屏模式
打开IOS视频全屏
VideoElement.webkitEnterFullscreen
接口可以打开 Video Element 元素的全屏:
const buttomElem = document.getElementById('myButton');
buttomElem.addEventListener('click', function() {
const videoDom = document.getElementById('videoDom');
if (videoDom?.webkitEnterFullscreen) {
// 打开全屏
videoDom.webkitEnterFullscreen();
}
}, false);
全屏后的视频是IOS的原生视频UI,这些原生UI并不能控制,所以也就没有关闭全屏之类的API。
IOS全屏变化事件
笔者找了一轮都没找到IOS视频全屏变化事件,最终使用了定时器的方法模拟了一个全屏事件:
let cleanVideoTimer = null;
function onFullScreenChange() {
cleanVideoTimer = setInterval(() => {
const videoDom = document.getElementById('videoDom');
if (videoDom?.webkitDisplayingFullscreen) {
// 视频元素处于全屏模式
} else {
// 视频元素退出全屏
}
}, 1000);
}
function offFullScreenChange() {
clearInterval(cleanVideoTimer);
}
IOS假全屏
IOS用的是原生的视频UI,因此不能自定义视频UI控件。解决方案是使用假全屏方案,即通过CSS的形式使video元素占满屏幕。
function openFullScreen() {
const videoDom = document.getElementById('video-dom');
// 用CSS撑满整个屏幕
videoDom.style.position = 'fixed';
videoDom.style.top = '0px';
videoDom.style.right = '0px';
videoDom.style.bottom = '0px';
videoDom.style.left = '0px';
videoDom.style.zIndex = '999';
}
function closeFullScreen() {
const videoDom = document.getElementById('video-dom');
videoDom.style.position = 'static';
videoDom.style.top = 'auto';
videoDom.style.right = 'auto';
videoDom.style.bottom = 'auto';
videoDom.style.left = 'auto';
videoDom.style.zIndex = '1';
}
此时全屏后的video元素是可控的HTML元素,想怎么自定义就怎么自定义。
B站的H5版本就是使用假全屏,但是假全屏不能做到真正全屏,浏览器的导航栏依然会显示:
总结
H5全屏可以使用原生Fullscreen API实现,但是不同的浏览器调用方式不一样,推荐第三方库screenfull实现全屏。 IOS只支持video元素全屏,调用API是IOS独有的API。IOS的全屏可操作的API比较少,如果不怕牺牲一些体验也可以使用假全屏的方案。
转载自:https://juejin.cn/post/7202809170378031160