ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于 Eventa IPC 的 Electron Vue 组合式 API 库 @proj-airi/electron-vueuse 实战指南

基于 Eventa IPC 的 Electron Vue 组合式 API 库 @proj-airi/electron-vueuse 实战指南 基于 Eventa IPC 的 Electron Vue 组合式 API 库 proj-airi/electron-vueuse 实战指南【免费下载链接】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本文围绕 AIRI 项目中面向 Electron 渲染进程的 VueUse 风格组合式函数composable集合proj-airi/electron-vueuse展开讲解它如何把鼠标跟踪、窗口边界、自动更新等 Electron 高频行为封装为可复用的 Vue 响应式 API并基于 Eventa 上下文/调用context/invoke模式打通渲染进程与主进程的 IPC 通信。读者读完可掌握该包的完整导出面、各 composable 的调用方式与参数语义以及主进程useLoop/createRendererLoop循环工具的用法并能据此在 AIRI 桌面应用中快速搭建自定义无边框窗口的交互逻辑。包定位与设计思路proj-airi/electron-vueuse是 AIRI monorepo 中的内部工具包private: true其定位在 README 中表述为 VueUse-like composables and helpers shared across AIRI Electron apps——即为所有 AIRI Electron 应用共享的、模仿 VueUse 风格的组合式函数与辅助工具集合。从 包清单 可以看到它的几个关键设计决策以 Eventa 为 IPC 基座依赖moeru/eventa提供defineInvoke、createContext以及proj-airi/electron-eventa提供 IPC 契约定义。以 VueUse 为交互基座直接依赖vueuse/core鼠标跟踪等能力复用了useMouse、useAsyncState、useIntervalFn等成熟实现。依赖版本约束peerDependencies要求electron 39 44且vue 3意味着该包面向较新的 Electron 版本设计。双入口导出exports定义了.渲染进程 composables输出dist/index.mjs与./main主进程循环工具输出dist/main/index.mjs两个子路径。一个值得强调的架构原则是IPC 的契约定义与使用侧分离。包内并不自行声明 Electron IPC 的 channel 名称而是统一从proj-airi/electron-eventa引入如electron.window.getBounds、cursorScreenPoint、bounds等事件与调用定义README 对此有明确说明IPC contract 定义请使用proj-airi/electron-eventa。这样 renderer 侧只写我要调用什么channel 字符串、参数类型、返回值类型都集中在契约包中维护。渲染进程入口与 Eventa 上下文基础设施渲染进程的全部公开 API 由 src/index.ts 统一导出覆盖四大类鼠标相关useElectronMouse、useElectronRelativeMouse、useElectronMouseInElement、useElectronMouseInWindow、useElectronMouseAroundWindowBorder窗口相关useElectronWindowBounds、useElectronWindowResize、useElectronAllDisplays自动更新useElectronAutoUpdater上下文基建useElectronEventaContext、useElectronEventaInvoke及测试辅助resetElectronEventaContextForTesting。其中最底层的是 use-electron-eventa-context.ts它把 Eventa 的 renderer 适配器封装成全局单例let sharedContext: EventaContext | undefined export function getElectronEventaContext(ipcRenderer?: IpcRendererLike): EventaContext { sharedContext ?? createContext(resolveIpcRenderer(ipcRenderer)).context return sharedContext } export function useElectronEventaContext(ipcRenderer?: IpcRendererLike): ShallowRefEventaContext { return shallowRef(getElectronEventaContext(ipcRenderer)) }resolveIpcRenderer的解析优先级值得注意如果调用方显式传入ipcRenderer则优先使用否则回退到globalThis.window?.electron?.ipcRenderer。若两者都不可用会抛出明确错误Electron ipcRenderer is not available. Pass it explicitly to useElectronEventaContext().——这在预加载脚本未把ipcRenderer暴露到window.electron的调试场景下非常有用。useElectronEventaInvoke则把契约对象转换为可调用函数export function useElectronEventaInvokeRes, Req, ResErr, ReqErr( invoke: InvokeEventaRes, Req, ResErr, ReqErr, context?: EventaContext, ) { return defineInvoke(context ?? getElectronEventaContext(), invoke) }README 中的官方示例正是这种模式的浓缩import { electron } from proj-airi/electron-eventa import { useElectronEventaInvoke } from proj-airi/electron-vueuse const openSettings useElectronEventaInvoke(electron.window.getBounds)调用openSettings()即可得到契约约定的返回值。由于契约包 electron/index.ts 中cursorScreenPoint、startLoopGetCursorScreenPoint、bounds、startLoopGetBounds等都是通过defineEventa/defineInvokeEventa声明的具名事件channel 命名如eventa:event:electron:window:bounds与消息体类型在编译期即可被校验渲染进程代码无需关心底层ipcRenderer.send/invoke细节。鼠标跟踪系列从屏幕坐标到窗口内元素命中鼠标相关 composable 是这套工具链的亮点它们把系统级鼠标位置转化为 Vue 响应式数据整体呈分层结构。屏幕级鼠标useElectronMouseuse-electron-mouse.ts 的核心思想是把 Electron 主进程推送的屏幕坐标事件转译为标准MouseEvent再喂给 VueUse 的useMousecontext.on(cursorScreenPoint, (event) { const e new MouseEvent(mousemove, { screenX: event.body?.x, screenY: event.body?.y }) sharedEventTarget?.dispatchEvent(e) })useElectronMouseEventTarget维护一个模块级共享的EventTarget单例首次调用时通过defineInvoke(context, startLoopGetCursorScreenPoint)()通知主进程启动光标位置轮询/推送循环。useElectronMouse在此基础上以type: screen调用useMouse得到的就是屏幕绝对坐标screenX/screenY这与浏览器内useMouse默认的页面坐标语义不同是理解后续所有派生 API 的基础。窗口相对坐标useElectronRelativeMouseuse-electron-relative-mouse.ts 是鼠标系列的数学中枢它同时消费屏幕坐标与窗口边界用computed求差得到窗口相对坐标const x computed(() mouse.x.value - windowX.value) const y computed(() mouse.y.value - windowY.value)窗口相对坐标对于鼠标悬停在窗口哪个位置这类判断至关重要也是下面几个 API 的实现基础。元素级命中useElectronMouseInElement / useElectronMouseInWindowuse-electron-mouse-in-element.ts 提供与 VueUseuseMouseInElement对齐的返回值elementX/elementY元素内相对坐标、elementPositionX/Y元素左上角位置、elementWidth/Height、isOutside、sourceType以及stop()。它的update()用getBoundingClientRect()计算元素位置并监听三类变化源useResizeObserver与useMutationObserverattributeFilter: [style, class]跟踪元素自身的尺寸/样式变化watch([targetRef, x, y], update)跟踪鼠标移动与目标切换scroll捕获阶段与resize事件处理页面滚动与窗口缩放。useElectronMouseInWindow则只是useElectronMouseInElement(undefined, options)的别名——把元素退化为整个document.body语义即鼠标是否在窗口内、位于窗口内的哪个相对位置。窗口边缘感应useElectronMouseAroundWindowBorderuse-electron-mouse-around-window-border.ts 是典型的自绘无边框窗口能力检测光标是否贴近窗口四边与四角用于显示自定义缩放手柄。它基于useElectronRelativeMouse的坐标与useElectronWindowBounds的尺寸做纯计算注释里明确写出设计意图——Fast path: no extra listeners; reuses existing mouse and window bounds streams即复用既有数据流、不额外挂监听器。它接受两个可选参数参数默认值语义threshold8距窗口边缘多少像素内算贴近pxovershoot同threshold允许鼠标略微越出窗口仍算贴近便于用户摸索到边缘返回值包括nearLeft/nearRight/nearTop/nearBottom、四个角nearTopLeft/nearTopRight/nearBottomLeft/nearBottomRight以及汇总的isNearAnyBorder均以模块级单例数据流驱动多个组件同时调用不会产生重复监听。窗口与显示器边界跟踪、窗口缩放与多屏枚举窗口边界useElectronWindowBoundsuse-electron-window-bounds.ts 与鼠标事件流同构模块级持有x/y/width/height四个ref首次调用时订阅 Eventa 的bounds事件并启动startLoopGetBounds推送循环之后所有调用者共享同一份响应式数据context.on(bounds, (event) { windowBoundsX.value event.body.x // ... y / width / height }) void defineInvoke(context, startLoopGetBounds)()返回值即{ x, y, width, height }四个Ref。窗口缩放Windows 专用useElectronWindowResizeuse-electron-window-resize.ts 提供无边框窗口在 Windows 平台的自定义缩放能力。handleResizeStart(e, direction)首先通过electron.app.isWindows契约校验平台非 Windows 直接返回随后preventDefault/stopPropagation并在document上注册mousemove与mouseup监听移动时计算screenX/screenY增量调用electron.window.resize({ deltaX, deltaY, direction })请求主进程调整窗口尺寸mouseup时移除监听。direction类型ResizeDirection同样来自proj-airi/electron-eventa。由于缩放逻辑需要拦截原生标题栏行为通常配合useElectronMouseAroundWindowBorder的isNearAnyBorder来切换cursor样式形成完整的边缘感应 → 光标变化 → 拖拽缩放交互闭环。多显示器枚举useElectronAllDisplaysuse-electron-all-displays.ts 是对多显示器场景的封装基于useAsyncState调用electron.screen.getAllDisplays并借助useIntervalFn每 5 秒自动刷新一次const { state: allDisplays, execute } useAsyncState(() getAllDisplays(), []) useIntervalFn(() { void execute() }, 5000)初始值为空数组适合在副屏布局、跨屏定位等场景中消费。自动更新useElectronAutoUpdateruse-electron-auto-updater.ts 把 electron-updater 的完整状态机暴露为响应式数据契约同样来自proj-airi/electron-eventa/electron-updater。它维护一个state: RefAutoUpdaterState默认{ status: idle }并派生三个常用判定isBusystatus为checking或downloadingcanDownloadstatus availablecanRestartToUpdatestatus downloaded。对外暴露四个操作函数均为useElectronEventaInvoke包装checkForUpdates、downloadUpdate、quitAndInstall以及初始化时拉取当前状态的getState。onMounted时先getState同步一次状态再订阅electronAutoUpdaterStateChanged事件持续更新两步都包了 try/catch避免在非完整环境中挂载报错。UI 层可据此渲染检查中 / 可下载 / 可重启更新等状态按钮。主进程循环工具useLoop 与 createRendererLoop主进程侧的工具通过子路径proj-airi/electron-vueuse/main导入README 给出了入口示例import { createRendererLoop } from proj-airi/electron-vueuse/main通用定时循环useLooploop.ts 提供带互斥防重入的定时循环。关键实现点默认间隔options.interval ?? 1000 / 60约 60Hz16.67ms契合光标/窗口边界跟踪的实时性需求Mutex 防重入使用 es-toolkit 的Mutex若上一轮fn()尚未结束异步任务较长本轮 tick 直接跳过避免回调堆积定时器使用moeru/std的setClockInterval/clearClockInterval而非原生setInterval生命周期autoStart默认为true构造时即启动返回值提供start/resume/pause/stop四个控制方法start与resume等价pause与stop等价。export interface LoopOptions { interval?: number autoStart?: boolean }感知渲染进程存活的循环createRendererLooprenderer-loop.ts 是面向主进程持续驱动渲染进程场景的增强封装它在useLoop之上增加了三项防御存活检查每轮 tick 先ensureRendererIsAvailable内部调用isRendererUnavailable(window)——即window.isDestroyed() || webContents.isDestroyed() || webContents.isCrashed()任一为真则停止循环错误熔断用attemptAsync包裹run()若错误消息包含Render frame was disposed before WebFrameMain could be accessedshouldStopForRendererError判定说明渲染帧已销毁主动stop()其他错误则原样抛出事件兜底stopLoopWhenRendererIsGone同时监听closed、webContents的destroyed与render-process-gone三个事件任一触发即停止循环。createRendererLoop的autoStart默认false需要显式调用start()而start()内部会再做一次存活检查保证不会对已销毁窗口启动循环。同文件还导出safeClose(window)——关闭前先检查渲染进程是否可用避免对已崩溃的窗口执行close()引发异常。createRendererLoop({ window, run: async () { /* 例如向渲染进程推送实时数据 */ }, interval: 1000 / 60, })组合示例一个自绘无边框窗口的典型用法将上述 API 组合起来即可在渲染进程中实现窗口边缘感应 光标样式切换 Windows 自定义缩放 状态栏自动更新提示的完整交互import { useElectronMouseAroundWindowBorder } from proj-airi/electron-vueuse import { useElectronWindowResize } from proj-airi/electron-vueuse import { useElectronAutoUpdater } from proj-airi/electron-vueuse import { computed, watch } from vue const { isNearAnyBorder, nearTop, nearBottom, nearLeft, nearRight } useElectronMouseAroundWindowBorder({ threshold: 8 }) const cursor computed(() { if (nearTop || nearBottom) return ns-resize if (nearLeft || nearRight) return ew-resize return default }) watch(cursor, (v) { document.body.style.cursor v }) const { handleResizeStart } useElectronWindowResize() // 在四个边缘的透明拖拽条上绑定 mousedowne handleResizeStart(e, bottom-right) const { state, isBusy, canDownload, canRestartToUpdate, checkForUpdates, downloadUpdate, quitAndInstall } useElectronAutoUpdater() // 按 isBusy / canDownload / canRestartToUpdate 渲染更新按钮状态在这个示例里useElectronMouseAroundWindowBorder提供边缘判定纯计算、零额外监听useElectronWindowResize处理 Windows 下的拖拽缩放useElectronAutoUpdater驱动更新 UI——三者共享同一条由useElectronEventaContext单例建立的 Eventa 数据流这正是该包shared across Electron apps设计目标的直观体现。测试与调试要点显式注入 ipcRendereruseElectronEventaContext(ipcRenderer)/useElectronEventaInvoke(invoke, context)都支持传入自定义 context便于在测试中替换真实 IPC 通道。重置单例resetElectronEventaContextForTesting()会把模块级sharedContext置空供测试用例之间隔离上下文状态。错误提示若在非 Electron 环境或未暴露window.electron.ipcRenderer调用会抛出Electron ipcRenderer is not available...错误这是定位环境配置问题的最快信号。契约一致性IPC 契约channel 名、消息体结构一律以proj-airi/electron-eventa为准渲染与主进程两侧应引用同一契约包避免字符串漂移。相关源码导航包说明与用法 README包配置与导出映射 package.json渲染进程全部导出 src/index.tsEventa 上下文基建 use-electron-eventa-context.ts鼠标系列 use-electron-mouse.ts、use-electron-relative-mouse.ts、use-electron-mouse-in-element.ts、use-electron-mouse-around-window-border.ts窗口系列 use-electron-window-bounds.ts、use-electron-window-resize.ts、use-electron-all-displays.ts自动更新 use-electron-auto-updater.ts主进程循环 src/main/loop.ts、src/main/renderer-loop.tsIPC 契约定义 packages/electron-eventa/src/electron/index.ts如cursorScreenPoint、startLoopGetCursorScreenPoint、bounds、startLoopGetBounds需要注意的是本包目前仅作为内部共享库被引用如 stage-pages 中已有将其移植复用的 TODO 标注使用时请以 monorepo 当前工作区版本为准IPC 契约若需扩展应优先在proj-airi/electron-eventa中声明而非在本包内硬编码。【免费下载链接】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),仅供参考
返回列表