ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Airi 项目中的 useDocumentVisibility 实战指南:响应式追踪页面可见性,优化后台资源调度

2026/9/11 12:45:52 拓冰建站 浏览量
Airi 项目中的 useDocumentVisibility 实战指南:响应式追踪页面可见性,优化后台资源调度 Airi 项目中的 useDocumentVisibility 实战指南响应式追踪页面可见性优化后台资源调度【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airiuseDocumentVisibility是 VueUse 提供的 Elements 类别组合式函数用于在 Vue 组件中响应式追踪document.visibilityState——即浏览器页面是否对用户可见。在本仓库Airi 桌面陪伴应用中它被真实落地在舞台布局的主题色采样逻辑里用于在页面不可见时暂停昂贵的背景取色计算。读完本文你将掌握该组合式的函数式用法、组件式用法、类型契约以及如何像本仓库一样用它做可见时才干活的资源调度优化。一、useDocumentVisibility 是什么useDocumentVisibility是 VueUse 库中归类于Elements类别的一个组合式函数见 .agents/skills/vueuse-functions/SKILL.md其唯一职责是响应式追踪document.visibilityState。在浏览器标准中Page Visibility API 通过document.visibilityState暴露页面的可见性状态通常为visible页面处于前台、对用户可见或hidden页面被切到后台、被最小化、被其他标签页遮挡。这个状态之所以重要是因为浏览器对不可见页面会降级定时器精度、暂停动画帧、限制网络请求因此应用层同样应该在页面隐藏时暂停高开销任务以省电、降功耗并提升用户体验。useDocumentVisibility的价值在于它把这个原生属性包装成一个响应式ShallowRef开发者无需手动监听visibilitychange事件、无需关心事件注册与清理模板与watch可以直接消费这个 ref。本仓库所有主要应用与包如 apps/stage-web/package.json、apps/stage-tamagotchi/package.json、packages/stage-ui/package.json 等都通过vueuse/core: catalog:依赖 VueUse版本统一由根目录 pnpm-workspace.yaml 的 catalog 解析为^14.4.0因此下文所有用法在当前仓库环境下开箱即用。二、函数式用法推荐这是最常用、也最符合组合式 API 风格的调用方式。在script setup langts中直接调用即可script setup langts import { useDocumentVisibility } from vueuse/core const visibility useDocumentVisibility() /script调用后visibility是一个ShallowRefDocumentVisibilityState其.value会随页面可见性变化自动更新。典型消费方式是在模板中渲染或配合watch响应状态切换script setup langts import { useDocumentVisibility } from vueuse/core import { watch } from vue const visibility useDocumentVisibility() watch(visibility, (state) { if (state visible) { // 页面回到前台恢复动画、恢复轮询、刷新数据 } else { // 页面隐藏暂停高开销任务、记录离开时间 } }) /script三、组件式用法若你更偏好模板驱动VueUse 为该函数提供了对应的无渲染组件UseDocumentVisibility通过作用域插槽暴露visibilitytemplate UseDocumentVisibility v-slot{ visibility } Document Visibility: {{ visibility }} /UseDocumentVisibility /template这种方式适合把可见性状态作为一段 UI 的局部上下文例如在调试面板中实时展示当前页面状态或在嵌套组件中避免重复调用。四、类型声明与选项原文档给出了完整的类型契约见 useDocumentVisibility.mdexport interface UseDocumentVisibilityOptions extends ConfigurableDocument {} export type UseDocumentVisibilityReturn ShallowRefDocumentVisibilityState export declare function useDocumentVisibility( options?: UseDocumentVisibilityOptions, ): UseDocumentVisibilityReturn关键点解读返回类型ShallowRefDocumentVisibilityState浅层 refDocumentVisibilityState是 Web 标准类型取值主要为visible | hidden。浅层响应意味着值替换即可触发更新开销极小。选项UseDocumentVisibilityOptions extends ConfigurableDocument继承 VueUse 的ConfigurableDocument约定即支持传入自定义document对象。这在SSR / 非浏览器环境下尤为重要——服务端渲染或 Electron 主进程场景中全局document可能不存在可通过该选项注入安全的替代对象避免直接引用未定义的全局变量。__NO_SIDE_EFFECTS__注解表明该函数是无副作用声明可被构建工具安全地进行 tree-shaking 与内联优化这也是 VueUse 对纯响应式封装函数的一贯标记。五、仓库实战用可见性状态守卫背景主题色采样文档之外最有价值的部分是本仓库真实的使用场景。在 packages/stage-layouts/src/composables/theme-color.ts 中useDocumentVisibility与useIntervalFn组合使用实现了页面可见时才刷新动态主题色的调度策略import { useDocumentVisibility, useIntervalFn } from vueuse/core export function useBackgroundThemeColor({ ... }) { const visibility useDocumentVisibility() // ... // Keep theme-color reasonably fresh for animated wave backgrounds without doing per-frame work. const { pause, resume } useIntervalFn(() { if (visibility.value ! visible) return if (selectedOption.value?.kind BackgroundKind.Wave themeColorsHueDynamic.value) void updateThemeColor() }, 250, { immediate: false }) }该实现theme-color.ts的业务逻辑值得拆解场景当舞台背景为动态波浪背景BackgroundKind.Wave且用户开启了动态主题色themeColorsHueDynamic时需要周期性每 250ms从背景元素上取样颜色并写入meta nametheme-color让浏览器地址栏颜色跟随背景变化。问题html2canvas取色是昂贵操作涉及整页克隆与像素采样见同文件的colorFromElement调用配置了scale: 0.5、sampleHeight: 20等采样参数。页面在后台时持续采样毫无意义——用户根本看不到只会白白消耗 CPU 与电池。方案在useIntervalFn的回调第一行就检查visibility.value ! visible直接短路返回。这比pause()更轻量定时器本身仍在跑间隔 250ms 的开销可忽略但最昂贵的取色与 DOM 克隆逻辑被完全跳过。这正是useDocumentVisibility的核心价值用一个响应式状态守卫把页面不可见转化为零成本的 early-return且代码可读性极高。六、对照原生 visibilitychange 的等价实现为了理解useDocumentVisibility替你做了什么可以对比仓库中另一处使用原生 API 的代码。apps/stage-tamagotchi/src/renderer/composables/model-settings-runtime-snapshot.ts 中渲染进程需要在页面重新可见时向模型设置的所有者窗口同步运行时快照const syncFromOwnerWhenVisible () { if (document.visibilityState visible) requestCurrent() } onMounted(() { requestCurrent() window.addEventListener(focus, syncFromOwner) document.addEventListener(visibilitychange, syncFromOwnerWhenVisible) }) onUnmounted(() { window.removeEventListener(focus, syncFromOwner) document.removeEventListener(visibilitychange, syncFromOwnerWhenVisible) })这段代码需要手动完成四件事手动document.addEventListener(visibilitychange, ...)注册监听在回调中手动判断document.visibilityState visible在onUnmounted中手动removeEventListener清理稍有不慎就会造成内存泄漏或重复触发每次切换标签页都要走一遍事件回调无法声明式地读取当前状态。而useDocumentVisibility把上述全部封装为调用一次、得到一个响应式 ref、VueUse 内部自动管理事件生命周期基于tryOnScopeDispose在组件卸载时自动清理。这也解释了为什么 SKILL.md 将useDocumentVisibility的 Invocation 规则标记为AUTO——在 Vue 应用中应优先用组合式函数替代手写事件监听。七、与 useWindowFocus 的分工在 Elements 类别中useDocumentVisibility常与useWindowFocus并列出现见 SKILL.md。二者容易混淆需要区分useDocumentVisibility追踪document.visibilityState页面被标签页切换、最小化、浏览器失焦都会变为hidden覆盖整个文档的可见性useWindowFocus追踪window的focus/blur事件只关注窗口级焦点多标签页下切走但窗口仍聚焦时不会触发。实践中的选择原则需要页面整体是否可被用户看到决定是否停掉渲染、动画、轮询时用useDocumentVisibility只关心窗口是否聚焦例如暂停键盘快捷键响应时用useWindowFocus。Airi 桌面端在标签页层面与窗口层面的状态同步需求并存两者各有适用位置。八、最佳实践小结结合原文档与本仓库实现可以沉淀出以下可复用经验页面隐藏即降载把useDocumentVisibility()返回的 ref 作为所有高开销周期性任务的守卫条件——定时器可以保留但重活取色、克隆 DOM、密集计算、网络轮询在hidden状态下直接跳过。watch 可见性做状态同步页面从后台回到前台时通常是刷新过期数据、重新采样、恢复动画的最佳时机参考model-settings-runtime-snapshot.ts中可见即同步的思路用watch(visibility, ...)声明式实现。SSR 场景注入 document需要服务端渲染时通过UseDocumentVisibilityOptions传入自定义 document避免直接触碰不存在的全局对象。优先组合式函数而非手写事件VueUse 已替你完成监听注册、卸载清理与响应式包装手写visibilitychange只会引入重复代码和泄漏风险。组合而非替代useDocumentVisibility描述的是可见性状态这一事实具体何时暂停、何时恢复由业务层通过useIntervalFn、watch等编排两者组合才能构成完整的资源调度方案。对于像 Airi 这样需要长时间驻留、后台运行实时语音对话与 3D 舞台渲染的桌面陪伴应用而言页面不可见时省下每一分算力直接关系到用户的设备续航与流畅度——useDocumentVisibility正是这一切的起点。【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考