4-2 头部功能:全屏功能组件
1. 全屏功能概述
全屏功能(Fullscreen)是管理后台头部导航栏的常见功能之一。它允许用户将整个页面(或指定元素)以全屏方式展示,隐藏浏览器的地址栏、工具栏等 UI 元素,从而获得更大的可视区域。
Fullscreen API 基础
浏览器原生 Fullscreen API 提供了以下核心方法:
| 方法 | 说明 | 调用方式 |
|---|---|---|
requestFullscreen() | 请求进入全屏 | element.requestFullscreen() |
exitFullscreen() | 退出全屏 | document.exitFullscreen() |
fullscreenElement | 获取当前全屏元素 | document.fullscreenElement |
fullscreenchange 事件 | 全屏状态变化时触发 | document.addEventListener('fullscreenchange', fn) |
浏览器兼容性
| 浏览器 | 标准方法 | 带前缀方法 | 备注 |
|---|---|---|---|
| Chrome 71+ | requestFullscreen | webkitRequestFullscreen | 完全支持 |
| Firefox 64+ | requestFullscreen | mozRequestFullScreen | 完全支持 |
| Safari 16.4+ | requestFullscreen | webkitRequestFullscreen | 完全支持 |
| Edge 79+ | requestFullscreen | - | 基于 Chromium,完全支持 |
| iOS Safari | 部分支持 | - | 仅 <video> 元素支持全屏 |
最佳实践:不要直接使用原生 API,而是使用 VueUse 的
useFullscreencomposable,它已经处理了浏览器兼容性和前缀问题。
2. VueUse useFullscreen 详解
2.1 基本 API
import { useFullscreen } from '@vueuse/core'
const {
isFullscreen, // ShallowRef<boolean> -- 当前是否全屏(响应式)
enter, // () => Promise<void> -- 进入全屏
exit, // () => Promise<void> -- 退出全屏
toggle, // () => Promise<void> -- 切换全屏状态
} = useFullscreen()
typescript
2.2 参数说明
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
target | MaybeElementRef | document.documentElement | 要全屏的目标元素,不传则全屏整个页面 |
options.autoExit | boolean | false | 组件卸载时是否自动退出全屏 |
2.3 对指定元素全屏
可以传入一个模板引用(template ref)来对特定元素进行全屏,例如视频播放器:
<script setup lang="ts">
import { useFullscreen } from '@vueuse/core'
import { useTemplateRef } from 'vue'
const videoRef = useTemplateRef('videoEl')
const { isFullscreen, enter, exit, toggle } = useFullscreen(videoRef)
</script>
<template>
<video ref="videoEl" src="/video.mp4" controls />
<button @click="toggle">
{{ isFullscreen ? '退出全屏' : '全屏播放' }}
</button>
</template>
vue
3. 全屏组件开发
3.1 组件结构
src/components/things/
└── FullScreen.vue
text
3.2 完整组件实现
<!-- src/components/things/FullScreen.vue -->
<script setup lang="ts">
import { useFullscreen } from '@vueuse/core'
// Props: 允许外部自定义渲染的标签类型
const props = withDefaults(defineProps<{
tag?: string
}>(), {
tag: 'i',
})
// 使用 useFullscreen composable
const { isFullscreen, toggle } = useFullscreen()
</script>
<template>
<component
:is="tag"
:class="isFullscreen ? 'i-ri:fullscreen-exit-line' : 'i-ri:fullscreen-line'"
class="cursor-pointer"
@click="toggle"
/>
</template>
vue
3.3 组件设计要点解析
(1) 动态组件 <component :is="tag">
使用 Vue 的动态组件(<component :is="...">)允许外部自定义渲染的标签类型:
<!-- 默认渲染为 <i> 标签 -->
<FullScreen />
<!-- 自定义为 <span> 标签 -->
<FullScreen tag="span" />
<!-- 自定义为 <div> 标签 -->
<FullScreen tag="div" />
vue
为什么使用动态组件而不是固定标签:
- 行内元素(
<i>、<span>)通常只有内容本身的大小 - 外部可能需要设置
padding、margin等样式 - 允许用户在不同场景下选择合适的标签
性能说明:动态组件通常配合
<keep-alive>在标签类型的组件中使用,用于缓存大量内容。但这里只渲染一个<i>元素,所以动态组件的开销与固定标签几乎一致,无需担心性能问题。
(2) 图标切换逻辑
通过 isFullscreen 状态动态切换 class:
isFullscreen = false → 显示 "进入全屏" 图标 (i-ri:fullscreen-line)
isFullscreen = true → 显示 "退出全屏" 图标 (i-ri:fullscreen-exit-line)
text
使用三元表达式在一行中完成切换:
:class="isFullscreen ? 'i-ri:fullscreen-exit-line' : 'i-ri:fullscreen-line'"
vue
(3) cursor-pointer 确保可点击体验
添加 cursor-pointer 类(对应 cursor: pointer)让用户在鼠标悬停时看到手型光标,明确提示该元素可点击。
3.4 图标 safelist 配置
由于使用了动态 class 绑定,UnoCSS 无法在编译时静态分析到这些图标类名,需要将它们加入 safelist:
// uno.config.ts
import { defineConfig } from 'unocss'
export default defineConfig({
// 其他配置...
safelist: [
// 全屏相关图标
'i-ri:fullscreen-line',
'i-ri:fullscreen-exit-line',
// 暗黑模式图标
'i-prime:moon',
'i-prime:sun',
],
})
typescript
4. 在页面中使用
4.1 基本使用
<!-- src/pages/index.vue -->
<script setup lang="ts">
import DarkModeToggle from '~/components/things/DarkModeToggle.vue'
import FullScreen from '~/components/things/FullScreen.vue'
</script>
<template>
<header class="flex items-center gap-4">
<!-- 暗黑模式切换 -->
<DarkModeToggle />
<!-- 全屏切换 -->
<FullScreen />
</header>
</template>
vue
4.2 自定义样式
全屏组件支持通过外部设置样式:
<template>
<!-- 设置图标大小 -->
<FullScreen class="text-2xl" />
<!-- 设置图标颜色 -->
<FullScreen class="text-blue-500" />
<!-- 使用 style 属性 -->
<FullScreen style="font-size: 2rem; color: blue;" />
<!-- 使用 UnoCSS 工具类 -->
<FullScreen class="text-sky-500" />
</template>
vue
4.3 自定义标签
<template>
<!-- 默认 <i> 标签 -->
<FullScreen />
<!-- 使用 <span> 标签 -->
<FullScreen tag="span" />
</template>
vue
5. 全屏功能的扩展应用
5.1 功能扩展方向
全屏功能
├── 基础全屏(本节实现)
├── 全屏 + 锁屏
│ └── 进入全屏后锁定页面,需要密码解锁
├── 全屏 + 桌面壁纸
│ └── 全屏时展示自定义壁纸图片
└── 全屏 + 计时器
└── 全屏专注模式,配合倒计时
text
5.2 退出全屏的方式
用户可以通过以下方式退出全屏:
| 方式 | 操作 | 说明 |
|---|---|---|
| 按键 | Escape | 浏览器默认行为,所有浏览器支持 |
| 组件按钮 | 点击退出全屏图标 | 需要自行实现 |
| API 调用 | exit() / toggle() | 编程方式退出 |
5.3 注意事项
- iOS Safari 限制:在 iOS Safari 上,只有
<video>元素支持全屏,普通元素无法全屏 - 用户手势要求:全屏 API 要求由用户手势触发(如 click),不能在异步回调或自动执行中调用
- 全屏下的样式:全屏模式下可以通过
::backdrop伪元素自定义背景
/* 自定义全屏背景 */
::backdrop {
background-color: rgba(0, 0, 0, 0.5);
}
css
6. 完整组件代码(TypeScript 增强)
以下是带有完整 TypeScript 类型的增强版本:
<!-- src/components/things/FullScreen.vue -->
<script setup lang="ts">
import { useFullscreen } from '@vueuse/core'
interface Props {
/** 渲染的标签类型,默认为 'i' */
tag?: string
}
const props = withDefaults(defineProps<Props>(), {
tag: 'i',
})
const { isFullscreen, toggle } = useFullscreen()
</script>
<template>
<component
:is="tag"
:class="[
isFullscreen ? 'i-ri:fullscreen-exit-line' : 'i-ri:fullscreen-line',
'cursor-pointer',
]"
@click="toggle"
/>
</template>
vue
7. 管理后台头部功能组件体系
至此,头部导航栏的两个基础功能组件已开发完成:
| 组件 | 文件 | 功能 | 核心 API |
|---|---|---|---|
DarkModeToggle | components/things/DarkModeToggle.vue | 暗黑模式切换 | usePreferredDark, useStorage |
FullScreen | components/things/FullScreen.vue | 全屏切换 | useFullscreen |
头部功能组件全景
管理后台头部导航栏
├── DarkModeToggle.vue ← 暗黑模式切换(本章)
├── FullScreen.vue ← 全屏切换(本章)
├── LocaleSwitch.vue ← 国际化切换(后续章节)
├── LockScreen.vue ← 锁屏功能(扩展)
└── UserAvatar.vue ← 用户头像/下拉菜单
text
关键词
useFullscreen-- VueUse 全屏 composable,封装浏览器 Fullscreen APIFullscreen API-- 浏览器原生全屏接口<component :is>-- Vue 动态组件,运行时决定渲染的标签safelist-- UnoCSS 配置项,确保动态 class 被正确打包isFullscreen-- 响应式布尔值,当前是否处于全屏状态cursor-pointer-- CSS 鼠标指针样式,提示元素可交互
↑