Skip to page content

useSoftFullscreen 组合式 API
v2.34+

useSoftFullscreen() composable 能让一个元素(或组件)占据整个视口,就像 QTable、QCarousel 和 QEditor 的 fullscreen 属性所做的那样——这些组件本身正是构建在它之上的。

它是一种“软”全屏:浏览器保持原样,只有页面本身发生变化;这与 AppFullscreen 插件不同,后者封装的是浏览器的 Fullscreen API。在全屏期间,该元素会被移动到 <body> 的末尾,并在其原来的位置留下一个占位符,这样它就能摆脱任何带有 overflow、transform 或自身层叠上下文(stacking context)的祖先元素的束缚。你需要为这一时刻给元素设置样式,而 Quasar 的 fullscreen CSS 类开箱即用地做到了这一点。

元素内部持有的任何焦点和光标位置都会在移动过程中保留下来。在 Capacitor 和 Cordova 应用中,手机的返回键会退出全屏状态(与这些组件的行为一致);除非你选择退出该行为,否则路由切换也会退出全屏。

TIP

在 SSR 或 SSG 模式的服务端,该 composable 不做任何事:inFullscreen 始终保持为 false,各个方法都是空操作(no-op)。

在组件之外使用

该 composable 也可以在 setup() 之外调用:在 boot 文件、store 或普通模块中。此时没有组件根元素可供回退,因此必须提供一个 target。在那种场景下路由切换不会退出全屏状态(没有任何东西把这次调用与路由器关联起来),并且不会有任何东西自动退出它:完成后请调用 exitFullscreen()。

语法

import { useTemplateRef } from 'vue'
import { useSoftFullscreen } from 'quasar'

setup () {
  const target = useTemplateRef('target') // an Element or a component

  const {
    inFullscreen, setFullscreen, exitFullscreen, toggleFullscreen
  } = useSoftFullscreen({
    // all optional:
    target,             // omit it for the component's own root element
    fullscreen: false,  // the requested state (declarative form)
    noRouteExit: false  // keep the state across route changes
  })

  // ...
}
function useSoftFullscreen(
  options?: MaybeRefOrGetter<{
    target?: MaybeRefOrGetter<
      Element | ComponentPublicInstance | null | undefined
    >
    fullscreen?: boolean
    noRouteExit?: boolean
  }>
): {
  inFullscreen: Ref<boolean>
  setFullscreen: () => void
  exitFullscreen: () => void
  toggleFullscreen: () => void
}

如果不提供 target,该 composable 会驱动它所在组件的根元素。一个渲染为片段(多个根节点)的组件没有单一的根元素可供移动,所以在这种情况下必须提供一个 target。

inFullscreen 是当前的状态。请在元素上把 fullscreen CSS 类(或你自己的类)绑定到它上面:

<template>
  <div ref="panel" :class="{ fullscreen: inFullscreen }">
    <q-btn
      flat
      :icon="inFullscreen ? 'fullscreen_exit' : 'fullscreen'"
      @click="toggleFullscreen"
    />
    <!-- ... -->
  </div>
</template>

<script setup>
  import { useTemplateRef } from 'vue'
  import { useSoftFullscreen } from 'quasar'

  const panel = useTemplateRef('panel')
  const { inFullscreen, toggleFullscreen } = useSoftFullscreen({
    target: panel
  })
</script>

你可以用两种方式来驱动这个状态:

  • 命令式:通过 setFullscreen()、exitFullscreen() 和 toggleFullscreen()
  • 声明式:通过 fullscreen 选项——每当该选项发生变化时,元素就会进入或退出全屏状态(如果挂载时该选项为 true,则一开始就处于全屏;如果在 target 尚不存在时发起请求,它会等到 target 出现)

声明式这种形式正是你自己组件的 fullscreen 属性所要映射到的写法。两种形式可以自由混用;该 composable 只在选项的值发生变化时才对其做出响应,因此你用命令式设置的状态会一直保持,直到该选项再次改变为止。对于 composable 自行执行的退出(手机返回键、路由切换)也是同样的道理:在选项仍为 true 的情况下,把它设为 false 再设回 true 即可重新进入全屏;或者让该选项与 inFullscreen 保持同步(一个 v-model 风格的属性正是这么做的)。

运行时更改选项

选项可以是一个普通对象、一个 Ref 或一个 getter 函数。普通对象只会被读取一次。如果传入 Ref 或 getter,该 composable 会追踪选项所读取的任何响应式状态,并在这些状态变化时重新应用选项:

  • 翻转 fullscreen 会进入或退出全屏状态
  • 在全屏期间把 target 指向另一个元素,会把当前元素放回原处;并且,如果全屏状态是通过 fullscreen 选项请求的,则会把新元素移到全屏。一个通过 v-if 消失的 target 会退出全屏状态;而当选项仍然要求全屏时,一旦它重新出现就会再次进入全屏
  • noRouteExit 作用于下一次路由切换

一个被 <KeepAlive> 保活的组件在被停用时会退出全屏状态。当它再次被激活时,只有在 fullscreen 选项要求全屏的情况下,它才会重新回到全屏。

示例

通过一个模板 ref(一个组件,代表它的根元素)实现的照片查看卡片:其工具栏按钮用于切换软全屏状态,照片会随之放大以填满整个视口。

<template>
  <div class="q-pa-md">
    <q-card
      ref="viewerRef"
      class="viewer column"
      :class="{ fullscreen: inFullscreen }"
    >
      <q-toolbar class="bg-primary text-white">
        <q-toolbar-title>Mountains</q-toolbar-title>
        <q-btn
          flat
          round
          dense
          :icon="inFullscreen ? 'fullscreen_exit' : 'fullscreen'"
          @click="toggleFullscreen"
        />
      </q-toolbar>

      <q-img
        src="https://cdn.quasar.dev/img/mountains.jpg"
        class="col"
        :ratio="inFullscreen ? void 0 : 16 / 9"
        fit="cover"
      >
        <div class="absolute-bottom text-subtitle2">
          {{
            inFullscreen
              ? 'Soft fullscreen: the photo fills the viewport'
              : 'Open the photo in soft fullscreen'
          }}
        </div>
      </q-img>
    </q-card>
  </div>
</template>

<script setup>
import { useTemplateRef } from 'vue'
import { useSoftFullscreen } from 'quasar'

const viewerRef = useTemplateRef('viewerRef') // a component: its root gets moved

const { inFullscreen, toggleFullscreen } = useSoftFullscreen({
  target: viewerRef
})
</script>