從 Rust 呼叫前端
本文檔包含關於如何從您的 Rust 程式碼與應用程式前端通訊的指南。若要查看如何從您的前端與您的 Rust 程式碼通訊,請參閱從前端呼叫 Rust。
您的 Tauri 應用程式的 Rust 端可以透過利用 Tauri 事件系統、使用通道或直接評估 JavaScript 程式碼來呼叫前端。
事件系統
Tauri 提供了一個簡單的事件系統,您可以使用它來在 Rust 和您的前端之間進行雙向通訊。
事件系統設計用於需要串流少量數據或您需要實作多消費者多生產者模式(例如,推播通知系統)的情況。
事件系統不適用於低延遲或高吞吐量的情況。有關針對串流數據優化的實作,請參閱通道章節。
Tauri 命令和 Tauri 事件之間的主要區別在於,事件沒有強型別支援,事件有效負載始終是 JSON 字串,使其不適合較大的訊息,並且不支援功能系統來精細控制事件數據和通道。
AppHandle 和 WebviewWindow 型別實作了事件系統特徵 Listener 和 Emitter。
事件可以是全域的(傳遞給所有監聽器)或 webview 特定的(僅傳遞給與給定標籤匹配的 webview)。
全域事件
要觸發全域事件,您可以使用 Emitter#emit 函數
use tauri::{AppHandle, Emitter};
#[tauri::command]fn download(app: AppHandle, url: String) { app.emit("download-started", &url).unwrap(); for progress in [1, 15, 50, 80, 100] { app.emit("download-progress", progress).unwrap(); } app.emit("download-finished", &url).unwrap();}
Webview 事件
要將事件觸發到由特定 webview 註冊的監聽器,您可以使用 Emitter#emit_to 函數
use tauri::{AppHandle, Emitter};
#[tauri::command]fn login(app: AppHandle, user: String, password: String) { let authenticated = user == "tauri-apps" && password == "tauri"; let result = if authenticated { "loggedIn" } else { "invalidCredentials" }; app.emit_to("login", "login-result", result).unwrap();}
也可以透過呼叫 Emitter#emit_filter 將事件觸發到 webview 列表。在以下範例中,我們將 open-file 事件發送到 main 和 file-viewer webview
use tauri::{AppHandle, Emitter, EventTarget};
#[tauri::command]fn open_file(app: AppHandle, path: std::path::PathBuf) { app.emit_filter("open-file", path, |target| match target { EventTarget::WebviewWindow { label } => label == "main" || label == "file-viewer", _ => false, }).unwrap();}
事件有效負載
事件有效負載可以是任何 可序列化 型別,該型別也實作了 Clone。讓我們透過使用物件在每個事件中發出更多資訊來增強下載事件範例
use tauri::{AppHandle, Emitter};use serde::Serialize;
#[derive(Clone, Serialize)]#[serde(rename_all = "camelCase")]struct DownloadStarted<'a> { url: &'a str, download_id: usize, content_length: usize,}
#[derive(Clone, Serialize)]#[serde(rename_all = "camelCase")]struct DownloadProgress { download_id: usize, chunk_length: usize,}
#[derive(Clone, Serialize)]#[serde(rename_all = "camelCase")]struct DownloadFinished { download_id: usize,}
#[tauri::command]fn download(app: AppHandle, url: String) { let content_length = 1000; let download_id = 1;
app.emit("download-started", DownloadStarted { url: &url, download_id, content_length }).unwrap();
for chunk_length in [15, 150, 35, 500, 300] { app.emit("download-progress", DownloadProgress { download_id, chunk_length, }).unwrap(); }
app.emit("download-finished", DownloadFinished { download_id }).unwrap();}
監聽事件
Tauri 提供了 API,用於在 webview 和 Rust 介面上監聽事件。
在前端監聽事件
@tauri-apps/api
NPM 套件提供了 API,用於監聽全域和 webview 特定的事件。
-
監聽全域事件
import { listen } from '@tauri-apps/api/event';type DownloadStarted = {url: string;downloadId: number;contentLength: number;};listen<DownloadStarted>('download-started', (event) => {console.log(`downloading ${event.payload.contentLength} bytes from ${event.payload.url}`);}); -
監聽 webview 特定的事件
import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';const appWebview = getCurrentWebviewWindow();appWebview.listen<string>('logged-in', (event) => {localStorage.setItem('session-token', event.payload);});
listen
函數會使事件監聽器在應用程式的整個生命週期內保持註冊狀態。要停止監聽事件,您可以使用 unlisten
函數,該函數由 listen
函數傳回
import { listen } from '@tauri-apps/api/event';
const unlisten = await listen('download-started', (event) => {});unlisten();
此外,Tauri 提供了一個實用函數,用於僅監聽一次事件
import { once } from '@tauri-apps/api/event';import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
once('ready', (event) => {});
const appWebview = getCurrentWebviewWindow();appWebview.once('ready', () => {});
在 Rust 上監聽事件
全域和 webview 特定的事件也會傳遞到在 Rust 中註冊的監聽器。
-
監聽全域事件
src-tauri/src/lib.rs use tauri::Listener;#[cfg_attr(mobile, tauri::mobile_entry_point)]pub fn run() {tauri::Builder::default().setup(|app| {app.listen("download-started", |event| {if let Ok(payload) = serde_json::from_str::<DownloadStarted>(&event.payload()) {println!("downloading {}", payload.url);}});Ok(())}).run(tauri::generate_context!()).expect("error while running tauri application");} -
監聽 webview 特定的事件
src-tauri/src/lib.rs use tauri::{Listener, Manager};#[cfg_attr(mobile, tauri::mobile_entry_point)]pub fn run() {tauri::Builder::default().setup(|app| {let webview = app.get_webview_window("main").unwrap();webview.listen("logged-in", |event| {let session_token = event.data;// save token..});Ok(())}).run(tauri::generate_context!()).expect("error while running tauri application");}
listen
函數會使事件監聽器在應用程式的整個生命週期內保持註冊狀態。要停止監聽事件,您可以使用 unlisten
函數
// unlisten outside of the event handler scope:let event_id = app.listen("download-started", |event| {});app.unlisten(event_id);
// unlisten when some event criteria is matchedlet handle = app.handle().clone();app.listen("status-changed", |event| { if event.data == "ready" { handle.unlisten(event.id); }});
此外,Tauri 提供了一個實用函數,用於僅監聽一次事件
app.once("ready", |event| { println!("app is ready");});
在這種情況下,事件監聽器會在第一次觸發後立即取消註冊。
通道
事件系統旨在成為應用程式中全域可用的簡單雙向通訊。在底層,它直接評估 JavaScript 程式碼,因此可能不適合發送大量數據。
通道旨在快速並傳遞有序數據。它們在內部用於串流操作,例如下載進度、子程序輸出和 WebSocket 訊息。
讓我們重寫我們的下載命令範例,以使用通道而不是事件系統
use tauri::{AppHandle, ipc::Channel};use serde::Serialize;
#[derive(Clone, Serialize)]#[serde(rename_all = "camelCase", tag = "event", content = "data")]enum DownloadEvent<'a> { #[serde(rename_all = "camelCase")] Started { url: &'a str, download_id: usize, content_length: usize, }, #[serde(rename_all = "camelCase")] Progress { download_id: usize, chunk_length: usize, }, #[serde(rename_all = "camelCase")] Finished { download_id: usize, },}
#[tauri::command]fn download(app: AppHandle, url: String, on_event: Channel<DownloadEvent>) { let content_length = 1000; let download_id = 1;
on_event.send(DownloadEvent::Started { url: &url, download_id, content_length, }).unwrap();
for chunk_length in [15, 150, 35, 500, 300] { on_event.send(DownloadEvent::Progress { download_id, chunk_length, }).unwrap(); }
on_event.send(DownloadEvent::Finished { download_id }).unwrap();}
當呼叫下載命令時,您必須建立通道並將其作為引數提供
import { invoke, Channel } from '@tauri-apps/api/core';
type DownloadEvent = | { event: 'started'; data: { url: string; downloadId: number; contentLength: number; }; } | { event: 'progress'; data: { downloadId: number; chunkLength: number; }; } | { event: 'finished'; data: { downloadId: number; }; };
const onEvent = new Channel<DownloadEvent>();onEvent.onmessage = (message) => { console.log(`got download event ${message.event}`);};
await invoke('download', { url: 'https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-schema-generator/schemas/config.schema.json', onEvent,});
評估 JavaScript
要直接在 webview 上下文中執行任何 JavaScript 程式碼,您可以使用 WebviewWindow#eval
函數
use tauri::Manager;
tauri::Builder::default() .setup(|app| { let webview = app.get_webview_window("main").unwrap(); webview.eval("console.log('hello from Rust')")?; Ok(()) })
如果待評估的腳本不是那麼簡單,並且必須使用來自 Rust 物件的輸入,我們建議使用 serialize-to-javascript crate。
© 2025 Tauri 貢獻者。CC-BY / MIT