在 airi 桌面应用中使用 VueUse useIdle:基于用户活跃度驱动的空闲状态检测实践
发布时间:2026/10/14 2:04:53 锦皓数字建站

人工智能AI AgentMCP 服务工具调用GUI 自动化语音数字人交互助手【免费下载链接】airi 自托管、归你拥有的 Grok 风格 AI 伴侣与 waifu / 赛博生命灵魂容器目标是接近 Neuro-sama 的高度支持实时语音聊天、Minecraft 和 Factorio 游玩支持 Web / macOS / Windows。项目地址https://gitcode.com/moeru-ai/airi点击查看免费下载useIdle是 VueUse 中用于跟踪用户是否处于不活跃状态的响应式组合式函数composable它通过监听一组浏览器事件自动推断空闲与活跃的切换并暴露idle、lastActive与reset三个可编程接口。本篇指南以 airi 仓库内收录的 useIdle 参考文档 为主体完整讲解其调用方式、选项参数与类型契约并结合 airi 中stage-ui-three的 VRM 空闲动画与stage-tamagotchi桌面端的空闲/休眠实践说明在 AI 伴侣类桌面应用中如何利用空闲状态驱动资源节能与行为切换。读完本文你将掌握useIdle的完整 API、自定义事件集的正确姿势以及把它接入 Vue 3 / Nuxt 项目的可运行方案。useIdle 的功能定位用户活跃度传感器useIdle属于 VueUse 功能分类中的Sensors传感器类别。在 airi 仓库的 vueuse-functions 技能清单 中它被描述为 Tracks whether the user is being inactive跟踪用户是否处于不活跃状态与useMouse、usePageLeave、useNetwork等传感器函数并列调用规则为AUTO即只要场景适用就应优先考虑使用。它解决的问题很直接在一段时间内用户没有任何操作时应用需要做出响应。典型场景包括暂停不必要的动画循环、降低渲染帧率以节约 CPU/GPU 与电量停止自动轮询、后台拉流等网络行为触发离开状态提示、锁屏或节能模式在 AI 伴侣类应用中切换到角色空闲待机动画或停止语音等待逻辑。在 airi 中空闲是一个被多处使用的概念详见下文仓库内的空闲实践而useIdle正是从 DOM 事件层面提供这一信号的标准工具。基础用法设定超时阈值并读取状态useIdle的签名很简洁第一个参数是超时时间毫秒超过该时长未检测到用户活动即认为进入空闲。默认超时时间为1 分钟。import { useIdle } from vueuse/core const { idle, lastActive } useIdle(5 * 60 * 1000) // 5 min console.log(idle.value) // true or false返回的两个核心响应式值返回值类型含义idleShallowRefboolean用户当前是否处于空闲状态lastActiveShallowRefnumber最近一次检测到用户活动的时间戳毫秒idle的初始值由initialState选项控制默认false即初始视为活跃lastActive则记录最近一次触发活跃事件的时间。两者都是浅层 refShallowRef读取时使用.value。需要说明的是airi 仓库的 pnpm-lock.yaml 锁定的vueuse/core版本为 14.4.0配合 Vue 3.5.x上述用法在该版本及多数现代 VueUse 版本中一致若项目中使用的是更早期版本请以实际安装版本的类型声明为准。编程式重置reset 与活跃回调的配合文档提供了一个非常实用的模式当用户从空闲状态恢复活动时可以通过reset()立即重启空闲计时器。它与useCounter配合的完整示例import { useCounter, useIdle } from vueuse/core import { watch } from vue const { inc, count } useCounter() const { idle, lastActive, reset } useIdle(5 * 60 * 1000) // 5 min watch(idle, (idleValue) { if (idleValue) { inc() console.log(Triggered ${count.value} times) reset() // restarts the idle timer. Does not change lastActive value } })这里有两个值得注意的语义细节reset()只重启计时器不修改lastActive。也就是说它仅把下一次判定空闲的倒计时归零而最近活跃时间戳保持原值。如果你需要同步刷新lastActive应配合用户活动事件自行更新。watch监听的是idle从false→true的切换。利用 Vue 的watch默认行为在进入空闲时执行副作用若需要在退出空闲true→false时也做处理需要把watch(idle, ...)改为传入 getter 或使用watch的回调参数判断前后值。该模式非常适合空闲计时 行为计数/日志埋点的场景例如统计用户离开桌面端应用的次数每次进入空闲时记录一次并立即重置以便精确度量单次会话中的活跃片段时间。组件式用法UseIdle除了组合式函数调用VueUse 还提供了对应的无渲染组件形式UseIdle适合在模板中直接使用作用域插槽scoped slottemplate UseIdle v-slot{ idle } :timeout5 * 60 * 1000 Is Idle: {{ idle }} /UseIdle /template组件的timeoutprop 对应useIdle的第一个参数插槽中可解构出idle等返回值。这种方式在需要把空闲状态直接映射到模板渲染例如显示离开中气泡、隐藏某些交互元素时更为直观无需在script setup中额外声明变量。选项参数详解UseIdleOptionsuseIdle的第二个参数是选项对象完整类型如下export interface UseIdleOptions extends ConfigurableWindow, ConfigurableEventFilter { /** * Event names that listen to for detected user activity * * default [mousemove, mousedown, resize, keydown, touchstart, wheel] */ events?: WindowEventName[] /** * Listen for document visibility change * * default true */ listenForVisibilityChange?: boolean /** * Initial state of the ref idle * * default false */ initialState?: boolean }三个选项各自的作用选项默认值说明events[mousemove, mousedown, resize, keydown, touchstart, wheel]用于判定用户活跃的监听事件名列表。默认覆盖鼠标移动/按下、窗口缩放、键盘输入、触摸与滚轮listenForVisibilityChangetrue是否监听document.visibilitychange。开启后页面重新可见visibilitychange回到visible也会被计为一次用户活动initialStatefalseidleref 的初始状态。默认认为初始是活跃的此外UseIdleOptions继承了两个基接口ConfigurableWindow允许传入自定义window对象通常用于测试或非浏览器环境模拟不传则回退到全局window。从默认事件集可以推断useIdle实际是在window上挂载mousemove、mousedown、resize、keydown、touchstart、wheel监听器并在任一事件触发时刷新计时。ConfigurableEventFilter允许通过eventFilter对事件做节流/防抖等过滤处理如与throttleFilter、debounceFilter组合控制活跃事件 → 重置计时的触发频率避免高频事件如mousemove带来不必要的开销。自定义events的示例——例如只关注键盘与鼠标按键忽略持续移动造成的误活跃const { idle } useIdle(3 * 60 * 1000, { events: [mousedown, keydown, touchstart], listenForVisibilityChange: true, })关闭listenForVisibilityChange的场景通常是应用在多窗口环境如 airi 的 Electron 多窗口架构中不希望标签页/窗口重新获得焦点这一行为被误判为用户亲自操作。返回值与类型契约UseIdleReturn 与 Stoppableexport interface UseIdleReturn extends Stoppable { idle: ShallowRefboolean lastActive: ShallowRefnumber reset: () void } /** * Tracks whether the user is being inactive. * * param timeout default to 1 minute * param options IdleOptions */ export declare function useIdle( timeout?: number, options?: UseIdleOptions, ): UseIdleReturnUseIdleReturn继承自 VueUse 的Stoppable契约。Stoppable是 VueUse 组合式函数家族中可停止能力的标准形态通常包含isActive/isPending等状态与stop()方法用于在组件卸载或不再需要时解除事件监听、释放资源。可以推断useIdle内部通过tryOnScopeDispose或显式返回的stop()来在作用域销毁时清理挂在window上的事件监听器从而避免内存泄漏——这也是useIdle能够放心在任意组件中反复调用的前提。一句话总结 API 契约入参一个超时时间与一组选项出参是空闲标志、最近活跃时间戳与一个只重置计时不清除记录的重置函数并且整体可以随时停止。从源码结构看实现原理虽然仓库内没有内置 VueUse 的源码但根据类型声明与默认值可以合理推断其实现机制计时模型内部维护一个setTimeout时长即timeout超时后将idle置为true一旦监听到任意活跃事件立即清除旧定时器、刷新lastActive为当前时间戳并重新计时同时把idle置回false。事件监听集合默认的 6 个事件覆盖了桌面与触屏的主要输入通道touchstart的存在说明它天然适配移动端。可见性兜底listenForVisibilityChange: true时额外监听document.visibilitychange当页面从 hidden 回到 visible 时视为活跃——这保证了切走再切回不会让应用误以为用户仍在空闲。初始状态initialState直接决定idle的初值默认false意味着从组件挂载到首次超时之间应用按用户在场处理。这些推断与 VueUse 官方文档对useIdle的说明一致读者可在实际接入后通过 DevTools 观察lastActive的时间戳变化来验证。仓库内的空闲实践airi 如何围绕空闲做文章虽然 airi 仓库当前并没有直接调用useIdle的现成代码但空闲这一状态在项目中被多处显式建模可以作为接入useIdle的绝佳结合点VRM 角色的空闲待机动画与眼部扫视在 VRMModel.vue 中角色模型支持通过idleAnimation属性指定空闲时的待机动画.vrma文件并在 animation.ts 中提供了两个与空闲行为直接相关的组合式函数useBlinkanimation.ts#L92-L152模拟自然的眨眼周期MIN_BLINK_INTERVAL1 秒与MAX_BLINK_INTERVAL6 秒之间随机决定下一次眨眼时机用正弦曲线驱动blink表情的 morph 值。useIdleEyeSaccadesanimation.ts#L154-L264在用户空闲时模拟眼球扫视saccade让角色的视线在注视目标附近随机游走randFloat(-0.25, 0.25)使其不至于死盯着一点产生活着的赛博生命观感。从代码注释simulate idle eye saccades与idleAnimation: animation src for model可以看出airi 的空闲概念是驱动角色表现层行为的关键信号。一个自然的结合方式是用useIdle(5 * 60 * 1000)判定用户离开空闲时切换到低功耗渲染模式或让角色的待机动画接管活跃时恢复注视交互——这正是useIdle输出信号与仓库现有idleAnimation/useIdleEyeSaccades能力的天然衔接点。桌面端的多窗口空闲与电源事件airi 的桌面端apps/stage-tamagotchi基于 Electron在 powerMonitor.ts 中监听系统级的suspend、resume、lock-screen、unlock-screen事件并通过事件总线广播给各窗口。这是操作系统层面的空闲信号而useIdle提供的是 DOM 事件层面的用户无操作信号两者互补系统休眠/锁屏 → 由powerMonitor处理窗口可见但用户长时间无操作 → 由useIdle处理。Controls Island 的空闲相位在桌面端的 use-controls-island-placement.ts 中悬浮控制岛的移动动画定义了ControlsIslandMotionPhase idle | leaving | entering | arriving相位模型idle表示岛停留在某个角落的静止状态。虽然这是动画状态机的命名但也印证了项目代码中统一的idle 即静止/无动作语义与useIdle的判定语义一致。使用建议与边界超时时间按场景选取默认 1 分钟对是否离开的判断偏激进对于 airi 这类常驻桌面的 AI 伴侣建议使用 510 分钟如5 * 60 * 1000避免用户阅读长文本时被频繁误判。合理收窄事件集默认事件包含mousemove与wheel在视频播放等场景中会造成持续活跃若只想感知真实交互可自定义events: [mousedown, keydown, touchstart]。配合Stoppable的停止能力在组件卸载或应用进入系统休眠时调用stop()解除监听避免 Electron 渲染进程长驻导致的事件泄漏。区分窗口不可见与用户空闲listenForVisibilityChange只解决页面重新可见时的刷新窗口最小化期间的判定仍依赖事件监听必要时与powerMonitor的锁屏/休眠事件配合形成完整的活跃度画像。SSR 注意useIdle依赖window事件服务端渲染Nuxt SSR期间不会真正监听应在客户端渲染阶段使用或通过ConfigurableWindow注入测试用 window 对象。结语useIdle以极小的 API 面一个超时参数、三个选项、三个返回值覆盖了用户是否在场这一高频需求其默认事件集与可见性兜底使其在 Web 与 Electron 桌面端都能开箱即用。在 airi 中它可以与既有的 VRM 空闲动画、useIdleEyeSaccades、电源事件服务无缝组合构成从系统级到DOM 级的完整空闲检测链路。掌握了useIdle的参数语义与重置/停止契约你便能在任何 Vue 3 / Nuxt 项目中快速落地空闲驱动的节能与行为切换逻辑。赞分享人工智能AI AgentMCP 服务工具调用GUI 自动化语音数字人交互助手【免费下载链接】airi 自托管、归你拥有的 Grok 风格 AI 伴侣与 waifu / 赛博生命灵魂容器目标是接近 Neuro-sama 的高度支持实时语音聊天、Minecraft 和 Factorio 游玩支持 Web / macOS / Windows。项目地址https://gitcode.com/moeru-ai/airi点击查看免费下载相关推荐如何安装komorebi平铺窗口管理器Scoop、WinGet与源码编译3种方式完整指南如何安装komorebi平铺窗口管理器Scoop、WinGet与源码编译3种方式完整指南 komorebi 是一款专为 Windows 10/11 打造的开源桌面应用VueUse useIdle 完全指南追踪用户空闲状态与自动重置计时器VueUse useIdle 完全指南追踪用户空闲状态与自动重置计时器 useIdle 是 VueUse Sensors传感器分类下的核心组合式函数用于前端react-use 的 useIdle Hook 详解基于交互事件实时追踪用户空闲状态react use 的 useIdle Hook 详解基于交互事件实时追踪用户空闲状态 导读 useIdle 是 react use package.jso前端上一篇中后台项目中的数据导出格式转换性能Naive Ui Admin效率优化指南下一篇前端框架架构Awesome Design Patterns 响应式与Composition API创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。