跳到主要内容

窗口管理

Tauri 提供了丰富的窗口管理 API,允许你创建、配置和控制应用窗口。

窗口基础

创建窗口

通过配置文件创建tauri.conf.json):

{
"app": {
"windows": [
{
"label": "main",
"title": "我的应用",
"width": 1200,
"height": 800,
"center": true,
"resizable": true
}
]
}
}

通过代码动态创建(Rust):

use tauri::WebviewWindowBuilder;

#[tauri::command]
async fn create_settings_window(app: tauri::AppHandle) -> Result<(), String> {
let window = WebviewWindowBuilder::new(
&app,
"settings", // 窗口标签(唯一标识)
tauri::WebviewUrl::App("settings.html".into())
)
.title("设置")
.inner_size(600, 400)
.min_inner_size(400, 300)
.center()
.resizable(true)
.build()
.map_err(|e| e.to_string())?;

Ok(())
}

窗口配置选项

选项类型说明
labelstring窗口唯一标识符
titlestring窗口标题
width / heightnumber窗口尺寸
minWidth / minHeightnumber最小尺寸
maxWidth / maxHeightnumber最大尺寸
x / ynumber窗口位置
centerboolean是否居中显示
resizableboolean是否可调整大小
maximizedboolean是否最大化
fullscreenboolean是否全屏
decorationsboolean是否显示边框和标题栏
alwaysOnTopboolean是否置顶
visibleboolean初始是否可见
transparentboolean是否透明背景
skipTaskbarboolean是否在任务栏隐藏

窗口控制

获取窗口实例

在 Rust 中:

// 通过 AppHandle 获取
let window = app.get_webview_window("main").unwrap();

// 在 Command 中注入
#[tauri::command]
fn do_something(window: tauri::WebviewWindow) {
// window 就是调用此命令的窗口
}

在前端中:

import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";

const currentWindow = getCurrentWebviewWindow();

窗口操作

最小化、最大化、关闭:

// Rust
window.minimize().unwrap();
window.maximize().unwrap();
window.unmaximize().unwrap();
window.close().unwrap();
// 前端
import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";

const window = getCurrentWebviewWindow();
window.minimize();
window.maximize();
window.unmaximize();
window.close();

显示/隐藏窗口:

window.show().unwrap();
window.hide().unwrap();

设置窗口属性:

window.set_title("新标题").unwrap();
window.set_size(tauri::Size::Logical(tauri::LogicalSize {
width: 800.0,
height: 600.0
})).unwrap();
window.set_position(tauri::Position::Logical(tauri::LogicalPosition {
x: 100.0,
y: 100.0
})).unwrap();
window.set_always_on_top(true).unwrap();
window.set_decorations(false).unwrap(); // 无边框窗口

无边框窗口

创建无边框窗口可以实现自定义标题栏:

let window = WebviewWindowBuilder::new(&app, "main", tauri::WebviewUrl::App("index.html".into()))
.decorations(false) // 移除系统边框
.transparent(true) // 可选:透明背景
.build()
.unwrap();

实现自定义标题栏

前端 HTML:

<div data-tauri-drag-region class="titlebar">
<span class="title">我的应用</span>
<div class="window-controls">
<button onclick="minimize()"></button>
<button onclick="maximize()"></button>
<button onclick="close()">×</button>
</div>
</div>

CSS:

.titlebar {
height: 32px;
background: #2d2d2d;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 12px;
-webkit-user-select: none;
user-select: none;
}

[data-tauri-drag-region] {
app-region: drag; /* 允许拖拽窗口 */
}

.window-controls button {
app-region: no-drag; /* 按钮不可拖拽 */
}

JavaScript:

import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";

const window = getCurrentWebviewWindow();

function minimize() {
window.minimize();
}

function maximize() {
window.toggleMaximize();
}

function close() {
window.close();
}

窗口事件

监听窗口事件

Rust 端:

use tauri::Manager;

pub fn run() {
tauri::Builder::default()
.setup(|app| {
let window = app.get_webview_window("main").unwrap();

// 监听窗口移动
window.on_window_event(|event| {
match event {
tauri::WindowEvent::Moved(position) => {
println!("窗口移动到新位置: {:?}", position);
}
tauri::WindowEvent::Resized(size) => {
println!("窗口调整大小: {:?}", size);
}
tauri::WindowEvent::CloseRequested { .. } => {
println!("窗口关闭请求");
}
tauri::WindowEvent::Focused(focused) => {
println!("窗口焦点状态: {}", focused);
}
_ => {}
}
});

Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

前端:

import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow";
import { listen } from "@tauri-apps/api/event";

const window = getCurrentWebviewWindow();

// 监听窗口大小变化
window.listen("tauri://resize", (event) => {
console.log("窗口大小变化:", event.payload);
});

// 监听窗口移动
window.listen("tauri://move", (event) => {
console.log("窗口移动:", event.payload);
});

// 监听窗口关闭
window.listen("tauri://close-requested", (event) => {
console.log("窗口即将关闭");
});

多窗口通信

窗口间发送事件

从 Rust 发送:

use tauri::{AppHandle, Emitter};

// 向特定窗口发送
app.emit_to("settings", "theme-changed", "dark").unwrap();

// 向所有窗口广播
app.emit("config-updated", &new_config).unwrap();

从前端发送:

import { emitTo, emit } from "@tauri-apps/api/event";

// 向特定窗口发送
await emitTo("settings", "theme-changed", { theme: "dark" });

// 向所有窗口广播
await emit("config-updated", config);

窗口状态保存

使用 tauri-plugin-window-state 插件保存窗口位置和大小:

安装插件:

cargo add tauri-plugin-window-state

注册插件:

pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_window_state::Builder::default().build())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

插件会自动保存和恢复窗口状态。

实战示例

创建带加载动画的启动窗口

Rust:

use tauri::WebviewWindowBuilder;

pub fn run() {
tauri::Builder::default()
.setup(|app| {
// 创建启动窗口
let splash = WebviewWindowBuilder::new(
app,
"splash",
tauri::WebviewUrl::App("splash.html".into())
)
.title("加载中...")
.inner_size(400, 300)
.decorations(false)
.always_on_top(true)
.center()
.build()
.unwrap();

// 创建主窗口(初始隐藏)
let main = WebviewWindowBuilder::new(
app,
"main",
tauri::WebviewUrl::App("index.html".into())
)
.title("我的应用")
.inner_size(1200, 800)
.visible(false)
.build()
.unwrap();

// 模拟加载过程
let splash_clone = splash.clone();
tauri::async_runtime::spawn(async move {
tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;

// 关闭启动窗口,显示主窗口
splash_clone.close().unwrap();
main.show().unwrap();
main.set_focus().unwrap();
});

Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

创建模态对话框窗口

#[tauri::command]
async fn show_modal_dialog(app: tauri::AppHandle) -> Result<(), String> {
// 禁用主窗口
let main_window = app.get_webview_window("main").unwrap();
main_window.set_enabled(false).unwrap();

// 创建对话框窗口
let dialog = WebviewWindowBuilder::new(
&app,
"dialog",
tauri::WebviewUrl::App("dialog.html".into())
)
.title("确认")
.inner_size(400, 200)
.decorations(false)
.always_on_top(true)
.center()
.build()
.map_err(|e| e.to_string())?;

// 监听对话框关闭
let main_clone = main_window.clone();
dialog.on_window_event(move |event| {
if matches!(event, tauri::WindowEvent::CloseRequested { .. }) {
main_clone.set_enabled(true).unwrap();
main_clone.set_focus().unwrap();
}
});

Ok(())
}

最佳实践

  1. 合理使用标签:为每个窗口设置有意义的标签,便于管理
  2. 延迟加载:非必要窗口延迟创建,减少内存占用
  3. 状态保存:使用插件保存窗口状态,提升用户体验
  4. 错误处理:窗口操作可能失败,始终处理错误情况

下一步