23.4.1 Rust 端发送事件
插件中的 Rust 代码通常可以访问 AppHandle 或 Window 实例,通过它们来发射事件。
use tauri::Emitter;
// 向所有窗口广播事件
app_handle.emit("plugin:my-plugin:file-changed", "/path/to/file")?;
// 或者只发送给特定窗口
window.emit("plugin:my-plugin:download-progress", 42)?;
事件名称推荐使用 plugin:<name>:<action> 格式,以避免和其它插件或应用自定义事件冲突。
如果需要发送结构化数据,可以传递一个实现了 serde::Serialize 的类型:
#[derive(serde::Serialize)]
struct Payload {
file_path: String,
status: String,
}
app_handle.emit("plugin:my-plugin:status-change", Payload {
file_path: "/path".into(),
status: "updated".into(),
})?;
23.4.2 前端监听事件
前端可以通过 Tauri 的 listen 方法订阅事件,并在窗口销毁时自动取消监听。
import { listen } from '@tauri-apps/api/event';
const unlisten = await listen('plugin:my-plugin:file-changed', (event) => {
console.log('文件变更:', event.payload); // 原始数据
});
// 如果需要在组件卸载时停止监听
// unlisten();
对于 TypeScript 项目,可以定义一个强类型的事件处理:
import { listen } from '@tauri-apps/api/event';
interface StatusChangePayload {
file_path: string;
status: string;
}
const unlisten = await listen<StatusChangePayload>(
'plugin:my-plugin:status-change',
(event) => {
console.log(event.payload.file_path); // 类型安全
}
);
23.4.3 一次性事件与应用级事件
除了 listen,Tauri 也提供 once 用于只监听一次的事件(例如初始化完成通知),以及 emit(在 1.x 中前端事件 API 不同,但概念一致)。插件也可以利用 Window::listen 在 Rust 侧监听前端发回的事件,形成双向通信。
23.4.4 真实示例:下载进度推送
假设我们开发一个文件下载插件,在下载过程中持续推送进度。
Rust 端(插件命令中发送进度):
use tauri::{AppHandle, Emitter};
#[tauri::command]
async fn download_file(app: AppHandle, url: String, save_path: String) -> Result<(), String> {
for progress in 0..=100 {
app.emit("plugin:downloader:progress", progress)
.map_err(|e| e.to_string())?;
// 模拟下载延迟
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
}
Ok(())
}
前端监听并更新进度条:
import { listen } from '@tauri-apps/api/event';
import { invoke } from '@tauri-apps/api/tauri';
async function startDownload() {
const unlisten = await listen('plugin:downloader:progress', (event) => {
const percent = event.payload;
updateProgressBar(percent);
if (percent === 100) {
unlisten(); // 下载完成,取消监听
}
});
await invoke('plugin:downloader|download_file', {
url: 'https://example.com/file.zip',
savePath: '/tmp/file.zip',
});
}
23.4.5 注意事项
- 性能:高频事件(如每秒数百次)可能造成 IPC 拥塞,建议在前端使用节流(throttle)处理,或者在 Rust 端合并频次。
- 串行化:事件负载需要可序列化,避免传递不可序列化的值(如文件句柄)。
- 安全性:敏感数据不要用事件广播,应只发送给授权的窗口,并在命令层做权限校验。
- 生命周期:前端窗口关闭后,监听会自动释放;若在全局作用域注册事件,记得在合适时机调用
unlisten()。
通过插件的事件系统,你可以让 Rust 后台与前端界面保持实时、轻量的数据同步,极大地增强了插件与用户交互的能力。