在桌面应用开发中,系统对话框是用户交互的关键一环——打开文件、保存文档、确认操作、显示警告,这些都需要调用操作系统原生的对话框,而不是用网页模拟的假弹窗。Tauri 通过 dialog 插件提供了完整的原生对话框支持,既可以在前端用 JavaScript/TypeScript 直接调用,也能在 Rust 后端通过命令触发,保持了一致的用户体验。
10.1.1 安装与配置
Tauri 2 将对话框功能抽离为独立插件,使用前需要安装:
前端依赖
npm install @tauri-apps/plugin-dialog
Rust 依赖
在 src-tauri/Cargo.toml 中添加:
[dependencies]
tauri-plugin-dialog = "2"
插件注册
在 src-tauri/src/lib.rs 的 tauri::Builder 中注册插件:
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_dialog::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
前端使用时需要先导入并检查权限(Tauri 2 的权限模型需要显式声明)。在 src-tauri/capabilities/default.json 中增加对话框权限:
{
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": [
"core:default",
"dialog:default"
]
}
10.1.2 文件选择对话框
让用户选择本地文件或文件夹是高频需求。前端调用 open 函数,可以指定文件类型过滤器、多选、目录模式等。
示例:选择单个图片文件
import { open } from '@tauri-apps/plugin-dialog';
async function selectImage() {
const file = await open({
multiple: false,
filters: [{
name: '图片',
extensions: ['png', 'jpg', 'jpeg', 'gif', 'webp']
}]
});
if (file) {
console.log('选中文件路径:', file);
// file 是完整路径字符串,不是 Web File 对象
}
}
选择文件夹
const folder = await open({
directory: true,
multiple: false,
title: '选择导出目录'
});
返回的结果在 Tauri 2 中是一个 string 或 string[](多选时),而不是 Electron 的 File 对象。如果需要读取文件内容,需要结合 fs 插件或 Rust 命令来操作本地文件。
在 Rust 后端调用对话框
有时候你可能希望在后端直接弹出对话框,比如某个命令需要用户确认打开某个文件:
use tauri::Manager;
use tauri_plugin_dialog::DialogExt;
#[tauri::command]
async fn open_file_from_rust(app: tauri::AppHandle) -> Result<String, String> {
let file_path = app.dialog()
.file()
.add_filter("文本文件", &["txt", "md"])
.blocking_open_file(); // 或使用异步 .open_file()
file_path.map(|p| p.to_string_lossy().into_owned())
.ok_or_else(|| "用户取消了选择".into())
}
10.1.3 文件保存对话框
保存文件和打开文件对话框类似,但会提示用户输入或确认文件名。
前端调用
import { save } from '@tauri-apps/plugin-dialog';
async function saveNote() {
const filePath = await save({
defaultPath: '未命名.md',
filters: [{
name: 'Markdown',
extensions: ['md']
}]
});
if (filePath) {
// 需要自行将内容写入该路径,例如通过 Rust 命令或 fs 插件
}
}
默认保存路径可以动态指定,比如根据用户主目录或最近使用的文件夹。save 返回的是用户选定的文件完整路径,应用需负责后续的写入操作。
10.1.4 消息提示对话框
消息提示框用于向用户展示一条信息,并等待用户确认(只有一个确认按钮)。
import { message } from '@tauri-apps/plugin-dialog';
await message('文件保存成功!', {
title: '提示',
kind: 'info' // 'info' | 'warning' | 'error'
});
message 会阻塞前端 JavaScript 执行,直到用户点击“确定”。类型参数 kind 可传入 info、warning 或 error,不同平台会显示不同的图标。
10.1.5 错误弹窗与询问对话框
ask 函数可创建带“是/否”或“确认/取消”的对话框,非常适合处理危险操作前的确认。
import { ask } from '@tauri-apps/plugin-dialog';
async function deleteItem() {
const yes = await ask('确定要删除此项目吗?此操作不可撤销。', {
title: '危险操作',
kind: 'warning',
okLabel: '删除',
cancelLabel: '取消'
});
if (yes) {
// 执行删除逻辑
}
}
Tauri 2 没有直接的 error 独立方法,实现错误弹窗通常用 message 并指定 kind: 'error',或者用 Rust 命令返回错误时由前端捕获并显示对话框。如果需要自定义错误弹窗的按钮,可以考虑用 ask 搭配错误样式,但建议保持系统原生行为。
在 Rust 中弹出消息框
如果 Rust 后端检测到严重错误需要立即通知用户,可以直接调用:
use tauri_plugin_dialog::DialogExt;
app.dialog()
.message("无法连接到服务器,请检查网络。")
.title("连接失败")
.kind(tauri_plugin_dialog::MessageDialogKind::Error)
.blocking_show();
但要注意,阻塞式对话框会暂停当前线程,因此在前端命令中调用 Rust 然后弹出对话框是更安全的方式。
10.1.6 实际应用中的注意事项
- 权限分离:在 Tauri 2 的权限模型中,对话框的调用同样需要权限声明。如果忘记配置
dialog:default,调用会静默失败或在控制台报错。 - 异步与阻塞:前端 API 是异步的,Rust 端提供
blocking_前缀的同步方法和异步方法。在 Tauri 命令中调用对话框时,尽量使用异步版本,避免阻塞主线程。 - 文件路径处理:对话框返回的路径是操作系统原生格式,Windows 下为
C:\...,macOS/Linux 为 Unix 路径。传递给 Rust 命令读写时无需转换,Tauri 内部会自动处理。 - 用户体验一致性:原生对话框的呈现完全符合用户的操作系统习惯,无需担心样式差异。这正是 Tauri 相比 Electron 自定义对话框的优势之一。
- 错误处理边界:如果用户在对话框中取消操作,
open/save返回null或undefined,务必判空后再进行后续处理。
将这些对话框组合起来,你的 Tauri 应用就像是真正的本地程序,而不再是“网页套了层壳”。