useSoftFullscreen() composable 能让一个元素(或组件)占据整个视口,就像 QTable、QCarousel 和 QEditor 的 fullscreen 属性所做的那样——这些组件本身正是构建在它之上的。
它是一种“软”全屏:浏览器保持原样,只有页面本身发生变化;这与 AppFullscreen 插件不同,后者封装的是浏览器的 Fullscreen API。在全屏期间,该元素会被移动到 <body> 的末尾,并在其原来的位置留下一个占位符,这样它就能摆脱任何带有 overflow、transform 或自身层叠上下文(stacking context)的祖先元素的束缚。你需要为这一时刻给元素设置样式,而 Quasar 的 fullscreen CSS 类开箱即用地做到了这一点。
元素内部持有的任何焦点和光标位置都会在移动过程中保留下来。在 Capacitor 和 Cordova 应用中,手机的返回键会退出全屏状态(与这些组件的行为一致);除非你选择退出该行为,否则路由切换也会退出全屏。
在 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>