1. 事件的工作方式
- 任意一端主动发送
Rust 可以调用 window.emit("event-name", payload) 向某个窗口发送事件,也可以使用 app_handle.emit("event-name", payload) 向所有窗口广播。前端则通过 @tauri-apps/api/event 中的 emit 函数主动发送事件到 Rust。
- 任意一端监听
前端使用 listen("event-name", callback) 订阅事件,Rust 端则通过 app.listen("event-name", callback) 或 window.listen("event-name", callback) 接收来自前端的推送。
- 一对多广播
同一个事件名可以被多个监听器订阅,发送一次所有人都会收到,非常适合状态同步或通知推送。
2. 前端 API(TypeScript)
import { listen, emit } from '@tauri-apps/api/event';
// 监听来自 Rust 的事件
const unlisten = await listen('backend-status', (event) => {
console.log('收到负载:', event.payload);
});
// 主动发送事件给 Rust
await emit('user-action', { id: 1, type: 'click' });
// 取消监听(防止内存泄漏)
unlisten();
3. Rust 端 API
use tauri::Manager;
// 在命令中发送事件给当前窗口
#[tauri::command]
fn trigger_event(window: tauri::Window) {
window.emit("backend-status", "准备就绪").unwrap();
}
// 在 setup 中监听前端事件
fn main() {
tauri::Builder::default()
.setup(|app| {
let handle = app.handle();
app.listen("user-action", |event| {
println!("收到前端事件: {:?}", event.payload());
});
Ok(())
})
.invoke_handler(tauri::generate_handler![trigger_event])
.run(tauri::generate_context!())
.expect("启动失败");
}
4. 使用场景
- 后端状态推送:比如长时间运行的任务进度更新、WebSocket 消息转发,Rust 主动通知前端刷新界面。
- 多窗口同步:在主窗口触发操作,通过事件广播通知其他窗口同步数据。
- 前端主动通知后端:比如快捷键触发、页面生命周期事件,前端无需等待后端响应,直接
emit即可。 - 去耦合的模块通信:不同功能模块通过事件通信,不必直接互相依赖。
5. 注意事项
- 载荷必须可序列化:事件携带的数据需要实现 Serde 的
Serialize/Deserialize,只支持 JSON 兼容的类型。 - 事件名是字符串:建议用短横线命名(如
user-login),避免命名冲突。 - 及时取消监听:长时间存在的监听(尤其是全局监听)在组件卸载或窗口关闭时应调用返回的
unlisten函数,防止后台持续回调造成意外行为。 - 不是响应-回复模式:如果你需要“发一个问题然后等答案”,应使用命令模式;事件更适合单向通知。
一句话概括:事件模式是 Tauri 的“神经网”,让 Rust 和前端可以自由地双向推送消息,解耦逻辑的同时保持界面实时响应,是构建实时交互应用不可或缺的机制。