3.4 系统级能力:文件、剪贴板、通知与快捷键


3.4 系统级能力:文件、剪贴板、通知与快捷键

本节摘要:文件对话框、剪贴板、系统通知、全局快捷键是桌面应用区别于网页的四项核心系统能力,全部由主进程模块提供、经 preload 白名单供页面调用。本节逐项讲正确用法与平台差异,给出统一的"能力接入模式",并用一个"快速笔记"功能把四项能力串成完整闭环。

四项能力,一个模式

先把共同模式说破:系统能力住在主进程,页面经白名单调用,权限心智围绕"最小暴露"设计。四项能力无一例外:

能力 主进程模块 关键 API 平台差异要点
文件对话框 dialog showOpenDialog / showSaveDialog 过滤器写法跨平台一致,多选行为一致
剪贴板 clipboard readText / writeText / readImage 富文本格式各平台支持的标记集不同
通知 Notification isSupported / show Windows 略过应用名与图标策略
全局快捷键 globalShortcut register / unregister 注册全局生效,用完必须注销

文件对话框的正确姿势是"给出上下文":让对话框认得所属窗口(模态归属)、给出扩展名过滤器(少打字少出错)、区分打开与保存两个语义。常见错误是在渲染进程里找 dialog(找不到)或忘了传窗口引用导致对话框在 macOS 上悬浮无主。

// 主进程:一个规范的"选择图片"处理器 const { ipcMain, dialog } = require('electron'); ipcMain.handle('image:pick', async (event) => { const win = BrowserWindow.fromWebContents(event.sender); // 对话框归属窗口 const result = await dialog.showOpenDialog(win, { title: '选择要导入的图片', properties: ['openFile', 'multiSelections'], // 支持多选 filters: [ { name: '图片', extensions: ['png', 'jpg', 'jpeg', 'webp'] }, { name: '所有文件', extensions: ['*'] } ] }); if (result.canceled) return []; // 用户取消是正常路径 return result.filePaths; });

剪贴板是四项里唯一双向的(读和写都要)。写文本、写图片直白;读的时候要有"剪贴板内容不属于你的应用"的觉悟——用户可能复制了密码。工程惯例:只在用户显式动作(点了"粘贴"按钮)时读取,读完即用不留存,更不要做"剪贴板监听"这种被系统逐步收紧的行为。

通知的两条纪律:先问 isSupported 再发(个别环境不支持);频控是礼貌更是留存率问题——连发三条通知的应用会被用户在系统设置里一键静音。通知的点击事件回到主进程回调里,通常的动作是唤起对应窗口(3.3 节的 show + focus 组合)。

// 主进程:一条可点击的系统通知 const { Notification } = require('electron'); function notifyExportDone(win, count) { if (!Notification.isSupported()) return; // 环境兜底 const n = new Notification({ title: '导出完成', body: `共导出 ${count} 条记录,点击查看`, silent: false }); n.on('click', () => { win.show(); win.focus(); }); // 点击通知唤起窗口 n.show(); }

全局快捷键是四项里最"贵"的——它注册的是整个系统的按键,注册多了会跟其他软件打架,用户换了键盘布局还可能失灵。纪律有三:只注册用户显式配置的快捷键(别硬编码一堆);应用退出前必须全部注销(will-quit 钩子里干这件事);注册失败要有降级提示而不是静默吞掉。

// 全局快捷键的登记与注销 const { globalShortcut, app } = require('electron'); app.whenReady().then(() => { const ok = globalShortcut.register('CommandOrControl+Shift+N', () => { toggleQuickNoteWindow(); // 唤起快速笔记(见下方案例) }); if (!ok) console.warn('快捷键注册失败,可能被其他应用占用'); }); app.on('will-quit', () => { globalShortcut.unregisterAll(); // 不注销 = 污染系统的按键地图 });

图:系统能力接入的统一模式

图:系统能力接入的统一模式

案例:快速笔记的四能力闭环

背景:产品要在应用里加"随手记":全局快捷键唤出输入框,输入内容后自动存入当天笔记文件,同时写一份到剪贴板,重要内容弹通知确认。

操作:全局快捷键唤出一个无边框小窗(3.3 节的窗口模式);提交时页面经桥调用 quicknote:append 通道;主进程处理器里串起三项能力——文件按日期追加写入(userData 目录下按天分文件)、剪贴板写入正文、超过阈值时发通知。

// 主进程:quicknote 处理器,三项能力一次串联 const fs = require('node:fs/promises'); const path = require('node:path'); ipcMain.handle('quicknote:append', async (_e, text) => { if (typeof text !== 'string' || !text.trim()) { throw new Error('笔记内容不能为空'); // 参数校验:白名单不是免检通道 } const day = new Date().toISOString().slice(0, 10); const file = path.join(app.getPath('userData'), `notes-${day}.md`); await fs.appendFile(file, `- ${text}\n`, 'utf8'); // 能力一:文件 clipboard.writeText(text); // 能力二:剪贴板 const { size } = await fs.stat(file); if (size > 1024 * 64) { // 单日超 64KB 提醒归档 notifyExportDone(mainWin, '今天的速记已经不少了'); } return { file, size }; });

结果:用户在任何应用里按快捷键、打字、回车、回原应用粘贴——四步完成一次记录,全程不切换焦点。上线后这个功能成了日活最高的入口。

解读:闭环的价值在于用系统能力把交互路径压到最短,每项能力单独看都不稀奇,串起来才产生"桌面软件感"。变式:若要支持 Markdown 实时预览,把小窗升级为双栏(复用主窗口组件),系统能力层零改动——这正是"能力与界面分离"模式的好处。

本节要点回顾

  • 统一模式:能力住主进程,页面走白名单,参数校验与结构化返回是标配;
  • 文件对话框:给窗口归属、给过滤器、取消是正常路径;
  • 剪贴板:显式动作才读、读完即用、不做后台监听;
  • 通知:isSupported 先行、频控礼貌、点击唤起窗口;
  • 全局快捷键:只注册用户配置项、will-quit 注销、失败降级提示;
  • 闭环思维:系统能力的价值在串联后把交互路径压到最短。

第三章完工,窗口有了骨骼、流水线和四肢。但能力越多,被觊觎的面就越大——第四章给这栋房子上锁。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U