托盘与窗口
桌面端托盘、窗口行为、single instance 和后台运行的设计边界
你将学到
- 窗口关闭时该退出应用还是隐藏到托盘
- 重复启动应用时怎么处理
- 托盘菜单该放哪些入口
- 后台运行该怎么给用户选择
桌面应用和网页最大的差异之一:它能出现在系统托盘里,也能控制窗口行为。先分清哪些是用户界面,哪些是系统行为。
窗口行为
桌面端的窗口行为包括启动、关闭、最小化、聚焦和打开外部链接。这些行为在 Tauri 的 Rust 侧配置,前端通过 adapter 感知状态变化。
最核心的设计决策是:用户点关闭按钮时,应用是真的退出,还是隐藏到系统托盘继续运行。
| 行为 | 适合的场景 | 用户预期 |
|---|---|---|
| 关闭即退出 | 工具类应用、不需要后台服务的应用 | 点关闭,进程结束 |
| 关闭隐藏到托盘 | 常驻后台的应用、有消息推送或定时任务的应用 | 点关闭,应用还在托盘里 |
模板默认是关闭即退出。如果你的产品需要隐藏到托盘,需要在 Rust 侧的关闭事件里拦截默认行为,改成隐藏窗口而不是退出进程。
不管选哪种,都要让用户知道会发生什么。隐藏到托盘时,第一次关闭时给个提示:"应用已最小化到系统托盘"。不要让用户以为应用已经退出,却在后台悄悄运行。
窗口 vs 托盘的分工
窗口和托盘解决不同的问题。窗口是用户的主要工作区域,托盘是应用的常驻入口。两者的行为要协调,但职责要分清:
| 关注点 | 窗口负责 | 托盘负责 |
|---|---|---|
| 用户交互 | 所有主要操作 | 快速动作(打开、退出) |
| 可见性 | 用户主动打开和关闭 | 始终可见(除非用户退出) |
| 通知 | 页面内提示 | 系统级通知(可选) |
| 生命周期 | 可以隐藏 | 进程结束才消失 |
Single Instance
用户可能会双击图标再启动一次。模板配置了 single instance:如果应用已经在运行,新启动的进程会把焦点切到已有窗口,而不是再开一个。
这个行为由 Tauri 的 single instance plugin 处理,不需要你在前端写额外逻辑。在 lib.rs 里注册 plugin 即可:
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
// 聚焦已有窗口
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
}
}))没有 single instance 的话,用户可能会同时开两个窗口,两个进程抢同一个 app data 文件,导致数据冲突。
系统托盘
系统托盘是桌面应用的常驻入口。即使主窗口关闭了,用户仍然可以通过托盘重新打开或退出应用。
托盘菜单通常放几个稳定动作:
| 菜单项 | 做什么 |
|---|---|
| Open / 打开窗口 | 重新显示并聚焦主窗口 |
| 检查更新 | 触发更新检查(如果启用了 updater) |
| Quit / 退出 | 彻底退出应用,进程完全结束 |
菜单项不要放太多。托盘是快速入口,不是第二个设置页。常见的错误是在托盘菜单里塞太多功能,结果用户找不到退出按钮。
托盘图标在不同系统上的表现有差异:macOS 的图标会出现在菜单栏右侧,Windows 在任务栏右侧的通知区域,Linux 取决于桌面环境。图标用单色 template image 在深色和浅色背景下都能看清。
后台运行设计建议
| 场景 | 建议 |
|---|---|
| 点击关闭按钮 | 明确是退出应用,还是隐藏到托盘 |
| 重复启动 App | 使用 single instance,聚焦已有窗口 |
| 托盘菜单 | 保留打开窗口、检查更新、退出这些稳定动作 |
| 后台运行 | 给用户明确开关,不要默认偷偷常驻 |
| 托盘图标 | 用单色 template image,适配深色和浅色菜单栏 |
验收
改完窗口或托盘相关代码后,在 Tauri 原生窗口里验证:
- 关闭窗口的行为符合产品预期(退出或隐藏)
- 重复启动时焦点切回已有窗口,没有开第二个实例
- 托盘菜单项都能正常响应
- 退出后进程完全结束(没有残留在后台)
- 退出重开后本地偏好还在
- 在 macOS、Windows 上分别验证托盘位置和图标表现
下一步
窗口和托盘搞清楚了,下一步去看 测试与验收,了解桌面端怎么分层验收代码、浏览器预览和原生窗口。
想和其他创造者交流?
这篇文档有问题?