系统对话框 #
一、对话框概述 #
1.1 对话框类型 #
| 类型 | 说明 | 使用场景 |
|---|---|---|
| 文件选择 | 选择文件或目录 | 打开文件 |
| 保存对话框 | 选择保存位置 | 保存文件 |
| 消息对话框 | 显示消息 | 确认、警告 |
| 确认对话框 | 确认操作 | 删除确认 |
1.2 安装插件 #
bash
pnpm add @tauri-apps/plugin-dialog
rust
// src-tauri/src/lib.rs
tauri::Builder::default()
.plugin(tauri_plugin_dialog::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
1.3 权限配置 #
json
// src-tauri/capabilities/default.json
{
"permissions": [
"dialog:default",
"dialog:allow-open",
"dialog:allow-save",
"dialog:allow-message",
"dialog:allow-ask",
"dialog:allow-confirm"
]
}
二、文件选择对话框 #
2.1 基本使用 #
typescript
import { open } from '@tauri-apps/plugin-dialog';
async function selectFile() {
const selected = await open({
multiple: false,
directory: false,
});
if (selected) {
console.log('Selected file:', selected);
}
}
2.2 多文件选择 #
typescript
import { open } from '@tauri-apps/plugin-dialog';
async function selectMultipleFiles() {
const selected = await open({
multiple: true,
directory: false,
});
if (selected) {
// selected 是数组
console.log('Selected files:', selected);
}
}
2.3 选择目录 #
typescript
import { open } from '@tauri-apps/plugin-dialog';
async function selectDirectory() {
const selected = await open({
directory: true,
multiple: false,
});
if (selected) {
console.log('Selected directory:', selected);
}
}
2.4 文件过滤器 #
typescript
import { open } from '@tauri-apps/plugin-dialog';
async function selectImageFile() {
const selected = await open({
multiple: false,
filters: [
{
name: 'Images',
extensions: ['png', 'jpg', 'jpeg', 'gif', 'webp'],
},
{
name: 'All Files',
extensions: ['*'],
},
],
});
return selected;
}
2.5 设置默认路径 #
typescript
import { open } from '@tauri-apps/plugin-dialog';
import { homeDir } from '@tauri-apps/api/path';
async function selectFromHome() {
const home = await homeDir();
const selected = await open({
defaultPath: home,
multiple: false,
});
return selected;
}
2.6 设置标题 #
typescript
import { open } from '@tauri-apps/plugin-dialog';
async function selectWithCustomTitle() {
const selected = await open({
title: '选择要打开的文档',
multiple: false,
});
return selected;
}
三、保存对话框 #
3.1 基本使用 #
typescript
import { save } from '@tauri-apps/plugin-dialog';
async function selectSaveLocation() {
const path = await save({
defaultPath: 'untitled.txt',
});
if (path) {
console.log('Save to:', path);
}
}
3.2 设置过滤器 #
typescript
import { save } from '@tauri-apps/plugin-dialog';
async function saveAsImage() {
const path = await save({
defaultPath: 'image.png',
filters: [
{
name: 'PNG Image',
extensions: ['png'],
},
{
name: 'JPEG Image',
extensions: ['jpg', 'jpeg'],
},
],
});
return path;
}
3.3 完整保存示例 #
typescript
import { save } from '@tauri-apps/plugin-dialog';
import { writeTextFile } from '@tauri-apps/plugin-fs';
async function saveFile(content: string, defaultName: string = 'untitled.txt') {
const path = await save({
defaultPath: defaultName,
filters: [
{
name: 'Text File',
extensions: ['txt'],
},
{
name: 'All Files',
extensions: ['*'],
},
],
});
if (path) {
await writeTextFile(path, content);
return path;
}
return null;
}
四、消息对话框 #
4.1 基本消息 #
typescript
import { message } from '@tauri-apps/plugin-dialog';
async function showMessage() {
await message('操作已完成', {
title: '提示',
kind: 'info',
});
}
4.2 消息类型 #
typescript
import { message } from '@tauri-apps/plugin-dialog';
// 信息
await message('这是一条信息', { kind: 'info' });
// 警告
await message('这是一条警告', { kind: 'warning' });
// 错误
await message('发生错误', { kind: 'error' });
4.3 错误处理示例 #
typescript
import { message } from '@tauri-apps/plugin-dialog';
async function handleOperation() {
try {
// 执行操作
await performOperation();
await message('操作成功完成', {
title: '成功',
kind: 'info',
});
} catch (error) {
await message(`操作失败: ${error}`, {
title: '错误',
kind: 'error',
});
}
}
五、确认对话框 #
5.1 基本确认 #
typescript
import { ask } from '@tauri-apps/plugin-dialog';
async function confirmAction() {
const confirmed = await ask('确定要执行此操作吗?', {
title: '确认',
kind: 'warning',
});
if (confirmed) {
console.log('用户确认');
} else {
console.log('用户取消');
}
}
5.2 删除确认 #
typescript
import { ask } from '@tauri-apps/plugin-dialog';
async function confirmDelete(fileName: string): Promise<boolean> {
return await ask(`确定要删除 "${fileName}" 吗?此操作无法撤销。`, {
title: '确认删除',
kind: 'warning',
okLabel: '删除',
cancelLabel: '取消',
});
}
// 使用
async function deleteFile(path: string) {
const fileName = path.split('/').pop() || path;
const confirmed = await confirmDelete(fileName);
if (confirmed) {
// 执行删除
await remove(path);
}
}
5.3 退出确认 #
typescript
import { ask } from '@tauri-apps/plugin-dialog';
import { getCurrentWindow } from '@tauri-apps/api/window';
async function setupCloseConfirmation() {
const window = getCurrentWindow();
await window.onCloseRequested(async (event) => {
const confirmed = await ask('确定要退出吗?未保存的更改将丢失。', {
title: '退出确认',
kind: 'warning',
okLabel: '退出',
cancelLabel: '取消',
});
if (!confirmed) {
event.preventDefault();
}
});
}
六、自定义按钮 #
6.1 自定义按钮文本 #
typescript
import { ask } from '@tauri-apps/plugin-dialog';
async function customButtons() {
const result = await ask('是否保存更改?', {
title: '保存',
kind: 'info',
okLabel: '保存',
cancelLabel: '不保存',
});
return result;
}
6.2 三选一对话框 #
typescript
import { confirm } from '@tauri-apps/plugin-dialog';
async function saveBeforeClose(): Promise<'save' | 'discard' | 'cancel'> {
const save = await confirm('是否保存更改?', {
title: '保存',
kind: 'info',
okLabel: '保存',
cancelLabel: '不保存',
});
if (save) {
return 'save';
}
const discard = await confirm('确定放弃更改吗?', {
title: '确认',
kind: 'warning',
okLabel: '放弃',
cancelLabel: '取消',
});
return discard ? 'discard' : 'cancel';
}
七、React 封装 #
7.1 对话框 Hook #
typescript
// hooks/useDialog.ts
import { open, save, message, ask } from '@tauri-apps/plugin-dialog';
export function useDialog() {
const selectFile = async (options?: Parameters<typeof open>[0]) => {
return open(options);
};
const selectDirectory = async () => {
return open({ directory: true });
};
const selectSavePath = async (defaultName?: string) => {
return save({ defaultPath: defaultName });
};
const showMessage = async (msg: string, title?: string) => {
await message(msg, { title });
};
const showError = async (msg: string, title?: string) => {
await message(msg, { title, kind: 'error' });
};
const showWarning = async (msg: string, title?: string) => {
await message(msg, { title, kind: 'warning' });
};
const confirm = async (msg: string, title?: string) => {
return ask(msg, { title, kind: 'warning' });
};
return {
selectFile,
selectDirectory,
selectSavePath,
showMessage,
showError,
showWarning,
confirm,
};
}
7.2 使用 Hook #
tsx
import { useDialog } from '../hooks/useDialog';
function FileEditor() {
const { selectFile, selectSavePath, confirm, showError } = useDialog();
const handleOpen = async () => {
const path = await selectFile({
filters: [{ name: 'Text', extensions: ['txt'] }],
});
if (path) {
// 打开文件
}
};
const handleSave = async () => {
const path = await selectSavePath('untitled.txt');
if (path) {
// 保存文件
}
};
const handleDelete = async () => {
const confirmed = await confirm('确定要删除吗?');
if (confirmed) {
// 删除
}
};
return (
<div>
<button onClick={handleOpen}>打开</button>
<button onClick={handleSave}>保存</button>
<button onClick={handleDelete}>删除</button>
</div>
);
}
八、最佳实践 #
8.1 错误处理 #
typescript
async function safeSelectFile() {
try {
const path = await open();
return path;
} catch (error) {
console.error('Failed to open dialog:', error);
return null;
}
}
8.2 用户友好提示 #
typescript
async function saveWithConfirmation(content: string) {
const path = await save({
defaultPath: 'untitled.txt',
title: '保存文件',
});
if (!path) {
// 用户取消
return false;
}
try {
await writeTextFile(path, content);
await message('文件保存成功', { title: '成功', kind: 'info' });
return true;
} catch (error) {
await message(`保存失败: ${error}`, { title: '错误', kind: 'error' });
return false;
}
}
九、总结 #
9.1 核心要点 #
| 要点 | 说明 |
|---|---|
| 文件选择 | open() 函数 |
| 保存对话框 | save() 函数 |
| 消息对话框 | message() 函数 |
| 确认对话框 | ask() 函数 |
| 过滤器 | filters 选项 |
9.2 下一步 #
现在你已经掌握了系统对话框,接下来让我们学习 系统托盘,了解如何创建系统托盘应用!
最后更新:2026-03-28