应用端实验室桌面应用
00 / 00

托盘与窗口

桌面端托盘、窗口行为、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 上分别验证托盘位置和图标表现

下一步

窗口和托盘搞清楚了,下一步去看 测试与验收,了解桌面端怎么分层验收代码、浏览器预览和原生窗口。

想和其他创造者交流?

这篇文档有问题?