- 人工智能
- AI Agent
- MCP 服务
- 工具调用
- GUI 自动化
- 语音
- 数字人
- 交互助手
【免费下载链接】airi
💖🧸 自托管、归你拥有的 Grok 风格 AI 伴侣与 waifu / 赛博生命灵魂容器,目标是接近 Neuro-sama 的高度;支持实时语音聊天、Minecraft 和 Factorio 游玩,支持 Web / macOS / Windows。
导读
useWebNotification是 VueUse 提供的一个响应式封装,它把浏览器原生 Notification API(Web Notifications API)变成了可直接用于 Vue 组合式 API 的 composable,让你可以用最少的样板代码完成「请求权限 → 展示通知 → 响应通知事件」的完整链路。在 Moeru AI AIRI 这类同时运行于 Web / macOS / Windows 的自托管 AI 伴侣项目中,它非常适合用于渲染进程中的结果反馈、任务完成提醒等场景。读完本文,你将掌握useWebNotification的全部选项、事件钩子与类型签名,并能对照仓库中 Electron 与 Capacitor 两套通知实现,判断在不同运行环境下该如何选择通知方案。
本文的关联参考文档位于 .agents/skills/vueuse-functions/references/useWebNotification.md,它是仓库内vueuse-functions技能(见 .agents/skills/vueuse-functions/SKILL.md)为 VueUse 各函数维护的标准参考之一,其中将useWebNotification归类于Browser(浏览器)类别,调用规则为AUTO(即:只要适用就应优先使用,而不是手写原生 API)。
核心用法:一条命令拉起完整通知链路
useWebNotification的名字里就带着 "Reactive"——它把Notification、权限状态、事件回调全部接入 Vue 的响应式系统。最小示例:
import { useWebNotification } from '@vueuse/core' const { isSupported, notification, permissionGranted, show, close, onClick, onShow, onError, onClose, } = useWebNotification({ title: 'Hello, VueUse world!', dir: 'auto', lang: 'en', renotify: true, tag: 'test', }) if (isSupported.value && permissionGranted.value) show()这段代码来自原参考文档,它演示了三个关键点:
isSupported先行判断:并非所有浏览器/运行环境都实现了 Notification API(例如部分隐私模式或旧版 WebView),isSupported作为Supportable的响应式标识,用于在展示前做能力探测;permissionGranted响应式权限状态:不需要手动调用Notification.permission,权限变化会自动反映到该ShallowRef上;show()直接展示:在权限已授予的前提下,调用show()即可弹出通知,无需手动new Notification(...)。
提示(原文档 Tip):应用能够发送通知的前提是用户已经授予权限;同时用户操作系统层面的通知设置也可能阻止预期行为(例如 Windows 的「专注助手」、macOS 的「勿扰模式」)。因此即使
permissionGranted为true,也不应假定通知一定可见。
事件钩子:onClick/onShow/onError/onClose
通知的生命周期事件(点击、展示、出错、关闭)在原生的Notification上是分散的事件回调,useWebNotification通过 VueUse 的createEventHook工具把它们统一成了可注册的钩子函数:
import { useWebNotification } from '@vueuse/core' const { onClick, onShow, onError, onClose } = useWebNotification() // ---cut--- onClick((evt: Event) => { // Do something with the notification on:click event... }) onShow((evt: Event) => { // Do something with the notification on:show event... }) onError((evt: Event) => { // Do something with the notification on:error event... }) onClose((evt: Event) => { // Do something with the notification on:close event... })这里onClick((evt) => {...})的返回值是一个带有off()方法的取消注册句柄,这一接口正是createEventHook的EventHookOn<T>类型(详见 .agents/skills/vueuse-functions/references/createEventHook.md 中的类型声明)。也就是说,useWebNotification底层复用了createEventHook的「on/off/trigger/clear」机制,事件监听可以随时注销,避免组件卸载后回调泄漏。
参数全解:WebNotificationOptions与UseWebNotificationOptions
以下两个接口是useWebNotification的全部可配置项,字段与默认值均来自原文档的类型声明:
WebNotificationOptions(对应原生Notification构造参数)
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
title | string | '' | 通知的标题(只读属性,展示在通知头部) |
body | string | '' | 通知的正文文本 |
dir | "auto" \| "ltr" \| "rtl" | '' | 通知文本方向,auto跟随语言环境,ltr/rtl强制左/右对齐 |
lang | string | ''(DOMString) | 通知的语言代码,如'en'、'zh-CN' |
tag | string | '' | 通知的 ID 标签,同tag的新通知会替换旧通知,用于去重与更新场景 |
icon | string | '' | 作为通知图标的图片 URL |
renotify | boolean | false | 当新通知替换旧通知时,是否再次提醒用户(发出声音/振动) |
requireInteraction | boolean | false | 通知是否保持激活直到用户点击或关闭,而非自动消失 |
silent | boolean | false | 是否静默,不发出声音和振动(与设备设置无关) |
vibrate | number[] | — | 振动模式数组,按 Vibration API 规范作用于带振动硬件的设备(如移动端) |
UseWebNotificationOptions(组合式配置)
export interface UseWebNotificationOptions extends ConfigurableWindow, WebNotificationOptions { /** * Request for permissions onMounted if it's not granted. * Can be disabled and calling `ensurePermissions` to grant afterwords. * * @default true */ requestPermissions?: boolean }- 继承
ConfigurableWindow:可通过window选项注入自定义的window对象,方便 SSR、测试或 iframe 等场景; requestPermissions(默认true):在组件挂载时若权限尚未授予,自动调用权限申请。如果你想推迟到某个用户交互(如点击按钮)时再申请,可将其设为false,之后手动调用返回的ensurePermissions()。
返回值全解:UseWebNotificationReturn
export interface UseWebNotificationReturn extends Supportable { notification: ShallowRef<Notification | null> ensurePermissions: () => Promise<boolean | undefined> permissionGranted: ShallowRef<boolean> show: ( overrides?: WebNotificationOptions, ) => Promise<Notification | undefined> close: () => void onClick: EventHookOn<Event> onShow: EventHookOn<Event> onError: EventHookOn<Event> onClose: EventHookOn<Event> }| 返回值 | 类型 | 说明 |
|---|---|---|
isSupported | 继承自Supportable | 当前环境是否支持 Notification API |
notification | ShallowRef<Notification \| null> | 最近一次展示的Notification实例引用,未展示时为null |
permissionGranted | ShallowRef<boolean> | 权限是否已授予,响应式跟踪 |
ensurePermissions | () => Promise<boolean \| undefined> | 手动申请权限;返回是否授予,未执行申请时返回undefined |
show | (overrides?: WebNotificationOptions) => Promise<Notification \| undefined> | 展示通知;可在调用时覆盖部分选项(如临时换body),返回新通知实例 |
close | () => void | 关闭当前通知 |
onClick/onShow/onError/onClose | EventHookOn<Event> | 四个生命周期事件钩子,注册回调并返回{ off }取消句柄 |
值得注意show(overrides)的设计:通知参数既可以在初始化时统一声明,也可以在展示时按需覆盖。例如初始化设置统一的title与tag,调用show({ body: '新消息' })只覆盖正文,这比每次手动new Notification(...)更契合响应式场景。
结合 AIRI 仓库:同一项目的三种通知实现
AIRI 是一个同时面向 Web、移动端(Capacitor)与桌面端(Electron)的跨端项目,通知能力在不同运行环境下有各自的实现路径,理解这些边界有助于判断useWebNotification的适用场景:
1. 浏览器环境:useWebNotification(本文主角)
@vueuse/core是仓库各应用与包的公共依赖,例如 apps/stage-pocket/package.json 中声明了"@vueuse/core": "catalog:",apps/stage-tamagotchi/package.json 同样如此。在纯 Web 渲染层,useWebNotification是标准的「前端响应式通知」方案——它的底层就是浏览器window.Notification,因此只能在渲染进程 / 浏览器标签页中使用。
2. Electron 桌面端:主进程Notification+ IPC
在桌面端apps/stage-tamagotchi中,通知由Electron 主进程的Notification(Node 侧 API)承担,而不是浏览器 API。以 Spotlight 快速问答窗口为例:
- 渲染进程在 apps/stage-tamagotchi/src/renderer/pages/spotlight.vue 中,问答完成后通过
electronSpotlightShowResultNotification这个 eventa 事件(见 apps/stage-tamagotchi/src/shared/eventa/index.ts)把结果正文交给主进程; - 主进程在 apps/stage-tamagotchi/src/main/windows/spotlight/index.ts 的
showNotification()中创建new Notification({ title: 'AIRI', body, ... })并监听close/failed/click事件。
这段实现里有一个值得借鉴的工程细节(源码注释中明确说明):Electron 可能会在构造作用域返回后将Notification对象 GC 回收,导致click处理器静默失效,因此代码用resultNotifications = new Set<Notification>()持有强引用,直到通知被close、failed或click后才释放。这一经验同样适用于浏览器端:如果你脱离useWebNotification手写new Notification(),也要警惕实例被垃圾回收导致事件丢失。
3. Capacitor 移动端:LocalNotifications插件
在移动端应用apps/stage-pocket中,通知走的是 Capacitor 原生插件@capacitor/local-notifications:
- 开发工具页 apps/stage-pocket/src/pages/devtools/notifications.vue 演示了完整的权限与调度流程:
checkPermissions()→(未授予时)requestPermissions()→schedule({ notifications: [...] }),支持id、title、body和schedule.at延迟调度; - 权限面板 apps/stage-pocket/src/components/permissions/permissions-panel.vue 还展示了更完善的权限治理:被拒绝时通过
capacitor-native-settings跳转系统设置(optionAndroid: AndroidSettings.AppNotification、optionIOS: IOSSettings.AppNotification),iOS 上还可以走requestPermission的写回逻辑。
也就是说,如果通知的目标设备是 Android/iOS,应使用LocalNotifications(原生通知、可持久调度);如果是桌面/浏览器渲染层,Web 端的useWebNotification与 Electron 主进程Notification才是对应方案。useWebNotification的isSupported在这些受限环境下会如实返回false,这也是它作为「能力探测 + 响应式封装」的价值所在。
典型实战模式
把上述知识点组合起来,一个符合仓库编码风格(组合式优先、事件钩子驱动)的完整用法如下:
import { useWebNotification } from '@vueuse/core' const { isSupported, permissionGranted, ensurePermissions, show, close, onClick, onShow, onError, onClose, } = useWebNotification({ title: 'AIRI', dir: 'auto', lang: navigator.language ?? 'zh-CN', tag: 'ai-result', renotify: false, requireInteraction: false, requestPermissions: false, // 延迟到用户交互时再申请 }) // 用户点击通知 → 聚焦聊天窗口 onClick(() => { // 处理点击跳转 }) onShow((evt) => { // 展示成功后的埋点/日志 }) onError((evt) => { // 展示失败时降级为应用内 toast }) async function onUserClickNotifyButton() { if (!isSupported.value) return if (!permissionGranted.value) { const granted = await ensurePermissions() if (!granted) return // 引导用户到系统设置开启通知 } await show({ body: '结果已就绪' }) } // 组件卸载时自动释放事件监听(createEventHook 的 off 语义) onScopeDispose(close)要点回顾:
- 用
requestPermissions: false+ensurePermissions()把权限申请绑定到明确的用户手势上,符合浏览器对通知权限的「须由用户触发」约束,也避免页面加载即弹权限框的糟糕体验; show(overrides)只覆盖本次需要的字段;- 事件钩子通过
createEventHook提供off()能力,配合onScopeDispose可确保组件销毁时资源被正确清理。
小结
useWebNotification把浏览器 Notification API 的权限、展示、事件三条链路全部响应式化,是 Vue 应用中「浏览器桌面通知」的标准实现。结合 AIRI 仓库可以看到完整的通知能力矩阵:Web 渲染层用useWebNotification,Electron 桌面端用主进程Notification并通过 IPC 转发(需注意 GC 导致的事件丢失问题),移动端则用 CapacitorLocalNotifications。掌握isSupported能力探测、permissionGranted/ensurePermissions权限治理、show(overrides)覆盖式展示与四个事件钩子,你就能在不同运行环境下写出既简洁又健壮的通知逻辑。
- 人工智能
- AI Agent
- MCP 服务
- 工具调用
- GUI 自动化
- 语音
- 数字人
- 交互助手
【免费下载链接】airi
💖🧸 自托管、归你拥有的 Grok 风格 AI 伴侣与 waifu / 赛博生命灵魂容器,目标是接近 Neuro-sama 的高度;支持实时语音聊天、Minecraft 和 Factorio 游玩,支持 Web / macOS / Windows。
相关推荐
REFramework 完整指南:从 1 个 DLL 到三步打造你自己的 RE 引擎 mod
REFramework 完整指南:从 1 个 DLL 到三步打造你自己的 RE 引擎 mod REFramework 是面向 RE(Resident Evil,
游戏开发逆向工程插件系统VueUse 的 useWebNotification:在 Vue 3 中响应式封装 Web Notification 桌面通知
VueUse 的 useWebNotification:在 Vue 3 中响应式封装 Web Notification 桌面通知 导读 useWebNotifi
前端AIRI 桌面伴侣通知实战:VueUse useWebNotification 组合式函数完整解析
AIRI 桌面伴侣通知实战:VueUse useWebNotification 组合式函数完整解析 本文以 VueUse 官方 useWebNotificati
人工智能AI 应用大模型AI Agent交互助手语音数字人后端前端桌面应用移动开发GUI 自动化MCP 服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考