浏览器中视频播放器的全屏方案

项目中涉及主动调用接口控制视频播放器的全屏,但是发现使用 requestFullscreen 接口的方式在 IOS Safari 浏览器中不生效。 调研了下不同 Web 播放器对于全屏的实现方案:

项目中涉及主动调用接口控制视频播放器的全屏,但是发现使用 requestFullscreen 接口的方式在 IOS Safari 浏览器中不生效。 调研了下不同 Web 播放器对于全屏的实现方案:

实现方案

实现方案参考了 xgplayer/video.js/DPlayer 等多个播放器,它们实现上大同小异,下面挑选了两个最具代表性的:

xgplayer

西瓜播放器的实现方式比较简单粗暴,他会遍历不同厂商提供的全屏接口并挨个尝试调用:

// 进入全屏
function getFullscreen(el = this.config.fullscreenTarget) {
  // ......
  const GET_FULLSCREEN_API = ['requestFullscreen', 'webkitRequestFullscreen', 'mozRequestFullScreen', 'msRequestFullscreen']
  try {
    for (let i = 0; i < GET_FULLSCREEN_API.length; i++) {
      const key = GET_FULLSCREEN_API[i]
      if (el[key]) {
        const ret =
          key === 'webkitRequestFullscreen'
            ? el.webkitRequestFullscreen(window.Element.ALLOW_KEYBOARD_INPUT)
            : el[key]()
        if (ret && ret.then) {
          return ret
        } else {
          return Promise.resolve()
        }
      }
    }
    return Promise.reject(new Error('call getFullscreen fail'))
  } catch (err) {
    return Promise.reject(new Error('call getFullscreen fail'))
  }
}

// 退出全屏
function exitFullscreen(el) {
  // ......
  const EXIT_FULLSCREEN_API = ['exitFullscreen', 'webkitExitFullscreen', 'mozCancelFullScreen', 'msExitFullscreen']
  try {
    for (let i = 0; i < EXIT_FULLSCREEN_API.length; i++) {
      const key = EXIT_FULLSCREEN_API[i]
      if (document[key]) {
        const ret = document[key]()
        if (ret && ret.then) {
          ret.catch(() => {
          })
          return ret
        } else {
          return Promise.resolve()
        }
      }
    }
    return Promise.reject(new Error('call exitFullscreen fail'))
  } catch (err) {
    return Promise.reject(new Error('call exitFullscreen fail'))
  }
}

video.js v10

video.js v10 版本中全屏只关注了 requestFullscreenwebkitRequestFullscreen 两个接口。 另外它调用了 IOS 独有的 webkitSetPresentationMode 接口, 在前两种接口都不支持的情况下尝试让 video 元素进入全屏。

export async function requestFullscreen(container: HTMLElement | null, media: EventTarget) {
  const doc = document as WebKitDocument;

  if (container && (doc.fullscreenEnabled || doc.webkitFullscreenEnabled)) {
    const el = container as WebKitFullscreenElement;

    if (isFunction(el.requestFullscreen)) {
      return el.requestFullscreen();
    }

    if (isFunction(el.webkitRequestFullscreen)) {
      return el.webkitRequestFullscreen();
    }
  }

  const webkitVideo = media as WebKitVideoElement;
  if (isFunction(webkitVideo.webkitSetPresentationMode)) {
    webkitVideo.webkitSetPresentationMode('fullscreen');
    return;
  }

  const video = media as unknown as MediaFullscreenCapability;
  if (isFunction(video.requestFullscreen)) {
    return video.requestFullscreen() as Promise<void>;
  }
}

export async function exitFullscreen(media: EventTarget) {
  const doc = document as WebKitDocument;

  const webkitVideo = media as WebKitVideoElement;
  if (webkitVideo.webkitPresentationMode === 'fullscreen' && isFunction(webkitVideo.webkitSetPresentationMode)) {
    webkitVideo.webkitSetPresentationMode('inline');
    return;
  }

  if (isFunction(doc.exitFullscreen)) {
    return doc.exitFullscreen();
  }

  if (isFunction(doc.webkitExitFullscreen)) {
    return doc.webkitExitFullscreen();
  }

  const video = media as unknown as MediaFullscreenCapability;
  if (isFunction(video.exitFullscreen)) {
    return video.exitFullscreen() as Promise<void>;
  }
}

注意事项

调用请求全屏的接口存在安全策略,需要瞬态用户激活。 简单来讲就是调用 requestFullscreen 等接口前,需要用户在浏览器上有过 UI 操作,包括这些事件:

  • keydown(有些特定按键除外)
  • mousedown
  • pointerdown
  • pointerup
  • touchend

不一定需要视频播放器响应这些事件,只需要用户在整个页面上有这些操作即可。如果没有激活,调用接口会异步抛出 TypeError

评论

0 条
内容

提交后会显示在评论区。

这里空空如也。

Nepsyn 的四叠半赛博空间Copyright © 2026 Nepsyn. All rights reserved.