Skip to content
字数
407 字
阅读时间
3 分钟
ts
export interface UseFullscreenOptions extends ConfigurableDocument {
  /**
   * Automatically exit fullscreen when component is unmounted
   *
   * @default false
   */
  autoExit?: boolean
}

const eventHandlers = [
  'fullscreenchange',
  'webkitfullscreenchange',
  'webkitendfullscreen',
  'mozfullscreenchange',
  'MSFullscreenChange',
] as any as 'fullscreenchange'[]

/**
 * Reactive Fullscreen API.
 *
 * @see https://vueuse.org/useFullscreen
 * @param target
 * @param options
 */
export function useFullscreen(
  target?: MaybeElementRef,
  options: UseFullscreenOptions = {},
) {
  const {
    document = defaultDocument,
    autoExit = false,
  } = options

  const targetRef = computed(() => unrefElement(target) ?? document?.querySelector('html'))
  const isFullscreen = ref(false)

  const requestMethod = computed<'requestFullscreen' | undefined>(() => {
    return [
      'requestFullscreen',
      'webkitRequestFullscreen',
      'webkitEnterFullscreen',
      'webkitEnterFullScreen',
      'webkitRequestFullScreen',
      'mozRequestFullScreen',
      'msRequestFullscreen',
    ].find(m => (document && m in document) || (targetRef.value && m in targetRef.value)) as any
  })

  const exitMethod = computed<'exitFullscreen' | undefined>(() => {
    return [
      'exitFullscreen',
      'webkitExitFullscreen',
      'webkitExitFullScreen',
      'webkitCancelFullScreen',
      'mozCancelFullScreen',
      'msExitFullscreen',
    ].find(m => (document && m in document) || (targetRef.value && m in targetRef.value)) as any
  })

  const fullscreenEnabled = computed<'fullscreenEnabled' | undefined>(() => {
    return [
      'fullScreen',
      'webkitIsFullScreen',
      'webkitDisplayingFullscreen',
      'mozFullScreen',
      'msFullscreenElement',
    ].find(m => (document && m in document) || (targetRef.value && m in targetRef.value)) as any
  })

  const fullscreenElementMethod = [
    'fullscreenElement',
    'webkitFullscreenElement',
    'mozFullScreenElement',
    'msFullscreenElement',
  ].find(m => (document && m in document)) as 'fullscreenElement' | undefined

  const isSupported = useSupported(() =>
    targetRef.value
    && document
    && requestMethod.value !== undefined
    && exitMethod.value !== undefined
    && fullscreenEnabled.value !== undefined)

  const isCurrentElementFullScreen = (): boolean => {
    if (fullscreenElementMethod)
      return document?.[fullscreenElementMethod] === targetRef.value
    return false
  }

  const isElementFullScreen = (): boolean => {
    if (fullscreenEnabled.value) {
      if (document && document[fullscreenEnabled.value] != null) {
        return document[fullscreenEnabled.value]
      }
      else {
        const target = targetRef.value
        // @ts-expect-error - Fallback for WebKit and iOS Safari browsers
        if (target?.[fullscreenEnabled.value] != null) {
          // @ts-expect-error - Fallback for WebKit and iOS Safari browsers
          return Boolean(target[fullscreenEnabled.value])
        }
      }
    }
    return false
  }

  async function exit() {
    if (!isSupported.value || !isFullscreen.value)
      return
    if (exitMethod.value) {
      if (document?.[exitMethod.value] != null) {
        await document[exitMethod.value]()
      }
      else {
        const target = targetRef.value
        // @ts-expect-error - Fallback for Safari iOS
        if (target?.[exitMethod.value] != null)
          // @ts-expect-error - Fallback for Safari iOS
          await target[exitMethod.value]()
      }
    }

    isFullscreen.value = false
  }

  async function enter() {
    if (!isSupported.value || isFullscreen.value)
      return

    if (isElementFullScreen())
      await exit()

    const target = targetRef.value
    if (requestMethod.value && target?.[requestMethod.value] != null) {
      await target[requestMethod.value]()
      isFullscreen.value = true
    }
  }

  async function toggle() {
    await (isFullscreen.value ? exit() : enter())
  }

  const handlerCallback = () => {
    const isElementFullScreenValue = isElementFullScreen()
    if (!isElementFullScreenValue || (isElementFullScreenValue && isCurrentElementFullScreen()))
      isFullscreen.value = isElementFullScreenValue
  }

  useEventListener(document, eventHandlers, handlerCallback, false)
  useEventListener(() => unrefElement(targetRef), eventHandlers, handlerCallback, false)

  if (autoExit)
    tryOnScopeDispose(exit)

  return {
    isSupported,
    isFullscreen,
    enter,
    exit,
    toggle,
  }
}

贡献者

chenjie
jiechen

文件历史