文件拖拽是桌面应用的基本交互,Tauri 支持双向拖拽:将系统文件拖入应用窗口,以及从应用拖出文件到系统(如桌面或文件夹)。这两种操作都能显著提升用户体验,比如拖入图片直接编辑,或拖出生成的文件直接保存。
1. 文件拖入应用
用户从系统的文件管理器(或桌面)拖动文件到 Tauri 窗口时,WebView 会触发原生的 drop 事件。你可以直接在前端监听这些事件,获取文件路径、文件名等信息。
基础实现
在前端,为需要接受拖放的区域添加事件监听:
document.addEventListener('dragover', (e) => {
e.preventDefault(); // 必须阻止默认行为才能接收 drop
});
document.addEventListener('drop', (e) => {
e.preventDefault();
const files = e.dataTransfer.files;
for (const file of files) {
console.log('拖入文件:', file.name, file.path); // file.path 是绝对路径
}
});
在 Tauri 中,拖入文件的 File 对象包含一个特殊的 path 属性(标准 Web API 没有暴露路径),你可以直接获取文件的绝对路径。然后通过 Tauri 的 Rust 命令进一步处理(例如读取内容、复制到工作目录等)。
启用拖放事件
默认情况下,Tauri 的 WebView 已经支持拖放。但如果你使用了 Tauri 的窗口自定义(无边框窗口),可能需要确保拖放区域未被禁用。在 tauri.conf.json 中无需额外配置。
读取拖入的文件内容
前端拿到路径后,可以调用 Rust 命令来读取文件:
Rust 侧:
#[tauri::command]
fn read_file(path: String) -> Result<String, String> {
std::fs::read_to_string(&path).map_err(|e| e.to_string())
}
前端调用:
import { invoke } from '@tauri-apps/api/core';
// 在 drop 事件中
const content = await invoke('read_file', { path: file.path });
这样,用户拖入一个文本文件就能立即在应用中看到内容。
拖放区域样式反馈
你可以监听 dragenter 和 dragleave 来高亮放置区域,提升交互体验。
2. 应用拖出文件到系统
从 Tauri 应用拖出文件到系统(例如桌面或打开的文件管理器)稍微复杂一些,因为 Web 标准对“拖出”的支持有限,而且无法直接提供物理文件给系统。Tauri 通过一个隐藏的文件写入 + 自定义拖拽数据的方式来实现。
实现思路
- 在 Rust 端生成要拖出的文件(例如先将数据写入临时目录)。
- 通过 Tauri 的事件系统,将文件的绝对路径发送给前端。
- 前端启动拖拽时,将文件路径设置到
DataTransfer中,并告诉系统这是一个文件。
不过,WebView 的 dragstart 事件允许设置 DataTransfer 的 effectAllowed 为 copy 或 move,但要真正让系统把文件当作“文件”处理,需要设置 files 属性。然而,DataTransfer.files 是只读的,不能直接赋值。因此,我们需要借助 Tauri 的原生拖拽 API(如 tauri-plugin-drag),或者通过系统剪贴板来模拟。
推荐方案:使用 tauri-plugin-drag 插件(Tauri v2 官方提供),它可以创建一个原生的拖拽操作,无需 hack。
使用 tauri-plugin-drag 实现文件拖出
- 安装插件:在
src-tauri/Cargo.toml添加依赖:
tauri-plugin-drag = "2"
并在 main.rs 中注册插件:
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_drag::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
- 前端使用:
import { startDrag } from 'tauri-plugin-drag/api';
// 假设用户点击某个元素开始拖拽
element.addEventListener('mousedown', async () => {
// 先由 Rust 生成文件,假设返回文件路径
const filePath = await invoke('generate_file');
// 启动原生的文件拖拽,系统会认为这是一个真实文件
await startDrag({
files: [filePath],
// 可选:设置拖拽时的图标
icon: 'path/to/icon.png',
});
});
startDrag 会触发一个原生拖拽操作,此时用户可以将文件拖到任何系统文件夹、桌面,就像从资源管理器中拖出一样。
如果没有使用插件,也可以手动模拟(不推荐)
你可以设置 dataTransfer.setData('DownloadURL', ...) ,某些系统(如 Windows 的某些浏览器)会识别并下载,但桌面应用的通用性较差,不建议作为主要方案。
安全与注意事项
- 拖入文件:获取到的路径是真实的文件系统路径,谨防路径遍历攻击。Rust 后端在处理路径时应使用
tauri::api::path解析,并限定在允许的目录内。 - 拖出文件:临时文件应合理清理,避免磁盘空间浪费。可以在应用退出时清空临时目录。
- 权限:在 Tauri v2 中,需要确保
tauri.conf.json里开启了fs相关的权限(如果拖入后要读写文件)。
实际应用场景
- 媒体编辑器:拖入图片/视频直接编辑,编辑完成后拖出保存到目标文件夹。
- 文档工具:从文件管理器拖入 Markdown 文件打开,修改后拖出生成 PDF。
- 下载管理器:下载完成后支持将文件直接拖到桌面。
通过内置的拖放事件和插件,Tauri 让文件拖拽操作既简单又自然,完全符合用户对桌面应用的预期。