likes
comments
collection
share

H5全屏API与视频全屏

作者站长头像
站长
· 阅读数 19

背景

做web视频的同学基本上逃不掉使用全屏API。之前笔者做了web视频相关的工作,也遇到一些全屏的坑,本文简单总结一下。下图是文章大纲:

H5全屏API与视频全屏 (上图使用笔者开发的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名称不一样了,请看下面的表格:

标准webkitFirefoxIE
打开全屏requestFullscreenwebkitRequestFullscreenmozRequestFullScreenmsRequestFullscreen
退出全屏exitFullscreenwebkitExitFullscreenmozCancelFullScreenmsExitFullscreen
全屏元素fullscreenElementwebkitFullscreenElementmozFullScreenElementmsFullscreenElement
是否支持全屏fullscreenEnabledwebkitFullscreenEnabledmozFullScreenEnabledmsFullscreenEnabled
全屏变化事件fullscreenchangewebkitfullscreenchangemozfullscreenchangeMSFullscreenChange
全屏报错事件fullscreenerrorwebkitfullscreenerrormozfullscreenerrorMSFullscreenError

如果要兼容所有的浏览器,需要判断不同的浏览器环境并使用对应的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);
  }
}

exitFullscreenfullscreenElement等其余的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 的兼容表:

H5全屏API与视频全屏

嗯,挺多绿的。但是细心观察的话会发现有个“刺头”:

H5全屏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全屏API与视频全屏

总结

H5全屏可以使用原生Fullscreen API实现,但是不同的浏览器调用方式不一样,推荐第三方库screenfull实现全屏。 IOS只支持video元素全屏,调用API是IOS独有的API。IOS的全屏可操作的API比较少,如果不怕牺牲一些体验也可以使用假全屏的方案。