人人都会AI编程

窗口间事件通信

更新时间:2026-07-11

在 Tauri 应用中,多窗口之间的通信是一个常见需求。例如,主窗口触发某个操作后,需要实时更新设置窗口的内容;或者多个窗口之间共享同一份数据状态,并同步变化。

Tauri 提供了一套简单的事件系统,让不同窗口之间可以轻松地发送和接收消息,无需额外的 IPC 管道或手动管理窗口引用。


核心 API

  • 前端发送事件:使用 @tauri-apps/api 提供的 emitemitTo 方法
  • 前端接收事件:使用 listen 监听事件
  • 后端(Rust)发送事件:通过 Window 实例的 emit 方法
  • 清除监听listen 返回一个取消监听的函数,避免内存泄漏

实际用法举例

场景:一个“记笔记”应用有两个窗口:主窗口(笔记列表)和编辑窗口(编辑单条笔记)。在编辑窗口中保存笔记后,需要通知主窗口刷新列表。

1. 编辑窗口:保存后发送事件

// 编辑窗口(editor.html 的 JavaScript)
import { emit } from '@tauri-apps/api/event';

async function saveNote(noteData) {
  // 调用 Rust 后端保存笔记
  await window.__TAURI__.invoke('save_note', { note: noteData });
  
  // 通知所有监听 'note-saved' 事件的窗口
  await emit('note-saved', { id: noteData.id });
}

2. 主窗口:监听事件并刷新列表

// 主窗口(main.html 的 JavaScript)
import { listen } from '@tauri-apps/api/event';

async function init() {
  // 监听 'note-saved' 事件
  const unlisten = await listen('note-saved', (event) => {
    console.log('收到事件,笔记ID:', event.payload.id);
    // 重新拉取笔记列表
    fetchNotes();
  });
  
  // 如果窗口被销毁,记得取消监听(例如在框架的 onDestroy 中调用 unlisten())
}

3. 如果只想发送给特定窗口

import { emitTo } from '@tauri-apps/api/event';

// 假设我们提前获取了主窗口的 label(窗口标识符)
await emitTo('main', 'note-saved', { id: noteData.id });

在创建窗口时,Rust 侧可以指定 label:

tauri::WindowBuilder::new(app, "main", /* url */);

前端通过 appWindow.label 可以知道当前窗口的 label。


从 Rust 手动发出事件

有时你希望在 Rust 逻辑中主动通知前端(例如文件监控、后台任务完成),可以直接使用 Windowemit 方法:

#[tauri::command]
async fn monitor_folder(window: tauri::Window) {
    // 模拟文件变化通知
    window.emit("folder-changed", "some/path").unwrap();
}

凡是通过 listen("folder-changed", ...) 监听的前端窗口都会收到。


注意事项

  • 事件名称推荐使用带前缀的标识,如 app:note-saved,避免与 Tauri 内部事件冲突。
  • payload 类型:支持任何可以被序列化(Serialize)的数据,对象、字符串、数字均可。
  • 内存管理:每次 listen 都会建立一个事件监听通道,务必在组件销毁或窗口关闭前调用返回的 unlisten 函数。
  • 跨窗口广播:默认 emit 会发送给所有窗口(包括自身),若只想通知其他窗口,可使用 emitToemitAll 的组合。

一句话总结:Tauri 的事件系统让多窗口通信变得像触发和监听自定义事件一样自然,窗口之间完全解耦,代码清晰且易于扩展。