首页 / 资讯中心 / 文章详情

tinyjs 原生菜单与对话框实战:菜单栏、右键菜单、文件选择与系统弹窗一篇搞定

tinyjs 原生菜单与对话框实战:菜单栏、右键菜单、文件选择与系统弹窗一篇搞定 ★ FEATURED ARTICLE
【免费下载链接】tinyjsappBuild native apps in JS. Backend, frontend. ~5Mb.项目地址https://gitcode.com/gh_mirrors/ti/tinyjsapp点击查看免费下载tinyjs 用不到 6MB 的运行时把原生菜单与系统对话框完整带进 JavaScript 桌面应用菜单栏、右键菜单、文件选择、alert/confirm 系统弹窗全部由操作系统原生渲染无需 Electron、Node 或捆绑 Chromium。本文从「跑起来一个应用」讲起带你用tiny.menu与tiny.dialog四组 API一次搞定桌面应用最常用的原生交互。一、为什么用原生菜单和系统弹窗用网页写桌面应用时有两件事 HTML 天生做不好菜单栏浏览器不会给你一条系统级菜单栏自己用 CSS 画又容易显得「假」文件对话框input typefile拿不到真实路径跨平台体验也不一致。tinyjs 的做法是让前端的tiny全局对象自动注入无需script引入把请求交给后端与原生 launchermacOS 上跑 NSOpenPanel / NSAlertWindows 上跑公共项对话框 MessageBoxLinux 上跑 GTK 选择器与消息框。你在页面上写的只是一行 JS用户看到的却是「长得像系统的一部分」的菜单和弹窗。二、一分钟跑起来tinyjs 应用基础 官方提供的一键安装脚本即可完成安装详见 README.md 的 Install 一节然后用脚手架命令创建并运行一个项目tinyjs new myapp cd myapp tinyjs dev窗口打开后项目结构长这样myapp/ tinyjs.json # 应用配置 src/backend/main.js # 后端有完整系统权限 src/frontend/ # 前端index.html js/css前端页面里可以直接使用tiny.*完整的 TypeScript 定义随框架附带在 template/types/tiny.d.ts 中可以看到每个菜单项、对话框参数的精确签名。三、菜单栏tiny.menu.set 快速定义完整菜单一个数组描述整条菜单tiny.menu.set接收「菜单 → 菜单项」的数组支持分隔线、勾选态、禁用态、快捷键和子菜单tiny.menu.set([ { title: 文件, items: [ { id: open, label: 打开…, key: o }, // key 对应 ⌘/Ctrl 按键 { id: save, label: 保存…, key: s }, { separator: true }, { id: quit, label: 退出, key: q }, ]}, { title: 工具, items: [ { id: mute, label: 静音, checked: true }, // ✓ 勾选态 { id: later, label: 稍后, enabled: false }, // 灰色禁用 { id: more, label: 更多, submenu: [ // 嵌套子菜单 { id: a, label: 子项 }, ]}, ]}, ]);两个小知识点每个菜单项建议给一个唯一id后续事件回调和更新都靠它tiny.menu.set设置的是应用菜单——之后打开的所有窗口都会显示它tiny.menu.update一次修补所有窗口的副本。处理点击事件与动态更新tiny.menu.on((id) { if (id open) openDoc(); if (id mute) toggleMute(); }); // 就地修补无需重新声明整条菜单 tiny.menu.update(mute, { checked: false, label: 取消静音 }); // 读取当前状态 const st await tiny.menu.get(mute); // { exists, label, checked, enabled }如果希望在后端处理点击比如需要读写文件导出onMenu(id, app)即可对应app.setMenu/app.updateMenuItem等同名方法。标准菜单角色Edit、应用菜单与帮助不同系统对「标准菜单」的约定不同tinyjs 用role字段帮你各归其位role作用editmacOS 的标准 Edit 菜单撤销/剪切/复制/粘贴默认占首位可手动放到任意位置app仅 macOS把项放进应用菜单About 与 Quit 之间Settings… 的规范位置help帮助菜单macOS 上永远排在最末并自带搜索框tiny.menu.set([ { title: 文件, items: [{ id: open, label: 打开…, key: o }] }, { role: edit }, // Undo / Cut / Copy / Paste / Select All { title: 视图, items: [{ id: full, label: 全屏, key: f }] }, ]); 想让三个平台的 Edit 菜单完全一致可以自己声明标准项{ role: edit, items: [{ role: standard }, { separator: true }, { id: find, label: 查找…, key: f }] }Windows/Linux 会显示快捷键但不会抢占 webview 自身的文本输入快捷键。四、右键菜单tiny.menu.setContext 自定义 Context Menuwebview 默认的右键菜单Reload、Inspect Element…带着浓浓的浏览器味。两步换成你自己的原生菜单在 tinyjs.json 中设置contextMenu: false彻底隐藏 WebKit 默认菜单用setContext声明自定义项格式与菜单栏完全相同tiny.menu.setContext([ { id: copy-path, label: 复制路径 }, { id: rename, label: 重命名… }, { separator: true }, { id: del, label: 删除 }, ]); tiny.menu.onContext((id) { if (id del) trashIt(); });传null可以恢复 webview 默认右键菜单标准角色{ role: copy }等同样可用托盘菜单与右键菜单共用同一套菜单项结构后端处理则导出onContextMenu(id, app)。五、文件选择tinyjs 原生文件对话框一步到位四个方法覆盖日常 90% 的文件操作返回值永远是真实文件系统路径用户取消则为nullAPI返回tiny.dialog.openFile()单个文件路径tiny.dialog.openFiles()路径数组tiny.dialog.pickFolder()文件夹路径tiny.dialog.saveFile()保存目标路径用types按扩展名过滤不带点用name预填保存文件名// 只能选 md / markdown / txt const file await tiny.dialog.openFile({ types: [md, markdown, txt] }); const dir await tiny.dialog.pickFolder(); // 预填 report.docx三个平台行为一致 const out await tiny.dialog.saveFile({ types: [docx], name: report });不再需要input typefile的各种兼容技巧也不再需要「把路径偷偷写进 input 再读出来」的 hack。六、系统弹窗alert / confirm / prompt 三件套浏览器里的confirm()在 webview 中体验糟糕tinyjs 提供原生系统弹窗应用级模态三大平台通用// 纯提示 await tiny.dialog.alert(导出完成, 共 42 页已保存到桌面); // 是 / 否 确认 → true | false const ok await tiny.dialog.confirm(删除全部笔记, { ok: 删除, cancel: 保留, }); // 输入框 → string | null取消为 null const name await tiny.dialog.prompt(你的名字, { default: world });实现层面这些弹窗由 launcher 在 UI 线程直接执行macOS 的 NSAlert、Windows 的 MessageBox、Linux 的 GTK 消息框并通过webview_return直接回应页面的 Promise——没有消息绕路体验就是系统原生弹框。七、进阶托盘菜单与多窗口菜单菜单栏应用tray app是「系统托盘 下拉菜单」的组合菜单项结构与tiny.menu完全一致tiny.tray.set({ icon: sf:cup.and.saucer.fill, // 或 png 路径 menu: [ { id: show, label: 显示窗口 }, { separator: true }, { id: quit, label: 退出 }, ], }); tiny.tray.on((id) { /* 菜单点击 */ }); tiny.tray.onClick(() toggle()); // 无 menu 时的左键点击搭配activation: accessory无 Dock 图标或mainWindow: false彻底无主窗口就能做出常驻菜单栏的小工具完整可运行的示例见 test/windowless-tray/。多窗口场景下tiny.win.menu.set / update / reset可以给某一个窗口单独换一条菜单栏想彻底隐藏菜单栏则用setChrome({ menu: false })快捷键依然有效。八、常见坑与排查清单 ⚠️types写扩展名时不带点[md, txt]写成[.md]过滤会失效弹窗取消返回nullopenFile等四个文件对话框都要显式判断取消别假设一定有值{ role: app }只在 macOS 有效Windows/Linux 没有应用菜单这些项会被丢弃——需要「设置」入口时在文件菜单里也声明一份快捷键抢占如果你的菜单项声明了key: c它会在整个应用包括文本框抢走 ⌘C请慎重右键菜单优先级setContext永远优先于 tinyjs.json 里的contextMenu: false配置Linux 托盘底层是 AppIndicator/StatusNotifier纯图标点击由合成菜单项模拟行为与 macOS 略有差异。九、延伸阅读 README.md安装、项目结构与完整 API 总览Menus、Dialogs 章节skill/references/api.md菜单与对话框 API 逐参数详解skill/references/recipes.md托盘/菜单栏应用等可抄配方template/types/tiny.d.tstiny.menu/tiny.dialog的 TypeScript 类型定义test/windowless-tray/无主窗口托盘应用完整示例赞分享【免费下载链接】tinyjsappBuild native apps in JS. Backend, frontend. ~5Mb.项目地址https://gitcode.com/gh_mirrors/ti/tinyjsapp点击查看免费下载相关推荐Godot 4 PopupMenu 实战指南从工具栏下拉菜单到右键上下文菜单与原生菜单集成Godot 4 PopupMenu 实战指南从工具栏下拉菜单到右键上下文菜单与原生菜单集成 PopupMenu 是 Godot 4 中用于展示选项列表的模态窗文档教程NodeGui QMenu 开发指南菜单栏、右键菜单与弹出菜单的构建及事件处理NodeGui QMenu 开发指南菜单栏、右键菜单与弹出菜单的构建及事件处理 QMenu 是 NodeGui基于 Node.js Qt 构建跨平台原生桌面应用跨平台LobeHub Desktop 菜单体系实战指南App 菜单、右键菜单与托盘菜单的配置原理LobeHub Desktop 菜单体系实战指南App 菜单、右键菜单与托盘菜单的配置原理 本篇基于 LobeHub 仓库中的 Desktop 菜单配置指南人工智能大模型AI AgentAI 应用多智能体前端后端本地部署工具调用创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站