窗口创建 #
一、窗口概述 #
1.1 窗口架构 #
Tauri 应用可以包含多个窗口,每个窗口都是独立的 WebView 实例。
text
┌─────────────────────────────────────────────────────────────┐
│ Tauri 应用 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 主窗口 │ │ 设置窗口 │ │ 关于窗口 │ │
│ │ main │ │ settings │ │ about │ │
│ │ │ │ │ │ │ │
│ │ WebView │ │ WebView │ │ WebView │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
1.2 窗口类型 #
| 类型 | 说明 | 使用场景 |
|---|---|---|
| 主窗口 | 应用启动时创建 | 主要界面 |
| 子窗口 | 动态创建 | 设置、详情页 |
| 模态窗口 | 阻塞父窗口 | 确认对话框 |
| 无边框窗口 | 无标题栏 | 自定义标题栏 |
二、配置创建窗口 #
2.1 在配置文件中定义 #
json
// tauri.conf.json
{
"app": {
"windows": [
{
"title": "My App",
"label": "main",
"width": 800,
"height": 600,
"resizable": true,
"fullscreen": false,
"center": true
},
{
"title": "Settings",
"label": "settings",
"width": 500,
"height": 400,
"resizable": false,
"visible": false
}
]
}
}
2.2 窗口配置选项 #
json
{
"label": "main",
"title": "Window Title",
"url": "index.html",
"width": 800,
"height": 600,
"minWidth": 400,
"minHeight": 300,
"maxWidth": 1200,
"maxHeight": 900,
"x": 100,
"y": 100,
"center": true,
"resizable": true,
"movable": true,
"minimizable": true,
"maximizable": true,
"closable": true,
"alwaysOnTop": false,
"fullscreen": false,
"fullscreenable": true,
"decorations": true,
"transparent": false,
"visible": true,
"skipTaskbar": false,
"theme": "system",
"titleBarStyle": "visible",
"hiddenTitle": false,
"acceptFirstMouse": false,
"tabbingIdentifier": null
}
三、动态创建窗口 #
3.1 后端创建窗口 #
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("Settings")
.inner_size(500.0, 400.0)
.resizable(false)
.build()
.map_err(|e| e.to_string())?;
Ok(())
}
3.2 前端创建窗口 #
typescript
import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
async function createSettingsWindow() {
const webview = new WebviewWindow('settings', {
url: 'settings.html',
title: 'Settings',
width: 500,
height: 400,
resizable: false,
});
// 监听窗口创建完成
webview.once('tauri://created', () => {
console.log('Settings window created');
});
// 监听创建错误
webview.once('tauri://error', (e) => {
console.error('Failed to create window:', e);
});
}
3.3 带预加载脚本的窗口 #
rust
use tauri::WebviewWindowBuilder;
#[tauri::command]
async fn create_window_with_preload(app: tauri::AppHandle) -> Result<(), String> {
let _window = WebviewWindowBuilder::new(
&app,
"custom",
tauri::WebviewUrl::App("custom.html".into())
)
.title("Custom Window")
.inner_size(600.0, 400.0)
.initialization_script(r#"
console.log('Window initialized');
window.customData = { initialized: true };
"#)
.build()
.map_err(|e| e.to_string())?;
Ok(())
}
四、窗口属性设置 #
4.1 设置标题 #
typescript
import { getCurrentWindow } from '@tauri-apps/api/window';
const window = getCurrentWindow();
// 设置标题
await window.setTitle('New Title');
4.2 设置大小 #
typescript
import { getCurrentWindow } from '@tauri-apps/api/window';
import { LogicalSize } from '@tauri-apps/api/dpi';
const window = getCurrentWindow();
// 设置大小
await window.setSize(new LogicalSize(800, 600));
// 设置最小大小
await window.setMinSize(new LogicalSize(400, 300));
// 设置最大大小
await window.setMaxSize(new LogicalSize(1200, 900));
4.3 设置位置 #
typescript
import { getCurrentWindow } from '@tauri-apps/api/window';
import { LogicalPosition } from '@tauri-apps/api/dpi';
const window = getCurrentWindow();
// 设置位置
await window.setPosition(new LogicalPosition(100, 100));
// 居中窗口
await window.center();
4.4 设置状态 #
typescript
import { getCurrentWindow } from '@tauri-apps/api/window';
const window = getCurrentWindow();
// 最小化
await window.minimize();
// 最大化
await window.maximize();
// 取消最大化
await window.unmaximize();
// 全屏
await window.setFullscreen(true);
// 置顶
await window.setAlwaysOnTop(true);
// 显示/隐藏
await window.show();
await window.hide();
// 聚焦
await window.setFocus();
五、窗口样式 #
5.1 无边框窗口 #
typescript
import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
const window = new WebviewWindow('frameless', {
url: 'frameless.html',
title: 'Frameless Window',
width: 800,
height: 600,
decorations: false,
transparent: true,
});
5.2 透明窗口 #
typescript
const window = new WebviewWindow('transparent', {
url: 'transparent.html',
title: 'Transparent Window',
width: 400,
height: 300,
transparent: true,
decorations: false,
});
css
/* 透明窗口样式 */
body {
background: transparent;
}
/* 半透明效果 */
.container {
background: rgba(255, 255, 255, 0.8);
backdrop-filter: blur(10px);
}
5.3 自定义标题栏 #
typescript
const window = new WebviewWindow('custom-titlebar', {
url: 'custom-titlebar.html',
title: 'Custom Titlebar',
width: 800,
height: 600,
decorations: false,
data: {
// macOS 特有配置
titleBarStyle: 'overlay',
hiddenTitle: true,
trafficLightPosition: { x: 10, y: 10 },
}
});
html
<!-- 自定义标题栏 HTML -->
<div class="titlebar" data-tauri-drag-region>
<span class="title">My App</span>
<div class="window-controls">
<button id="minimize">─</button>
<button id="maximize">□</button>
<button id="close">×</button>
</div>
</div>
typescript
// 窗口控制按钮
import { getCurrentWindow } from '@tauri-apps/api/window';
const window = getCurrentWindow();
document.getElementById('minimize')?.addEventListener('click', () => {
window.minimize();
});
document.getElementById('maximize')?.addEventListener('click', () => {
window.toggleMaximize();
});
document.getElementById('close')?.addEventListener('click', () => {
window.close();
});
六、窗口生命周期 #
6.1 监听窗口事件 #
typescript
import { getCurrentWindow } from '@tauri-apps/api/window';
const window = getCurrentWindow();
// 窗口关闭请求
await window.onCloseRequested(async (event) => {
const confirmed = await confirm('确定要关闭吗?');
if (!confirmed) {
event.preventDefault();
}
});
// 窗口获得焦点
await window.onFocusChanged(({ payload: focused }) => {
console.log('Focus changed:', focused);
});
// 窗口大小改变
await window.onResized(({ payload: size }) => {
console.log('Resized:', size);
});
// 窗口移动
await window.onMoved(({ payload: position }) => {
console.log('Moved:', position);
});
// 窗口最大化状态改变
await window.onMaximized(({ payload: maximized }) => {
console.log('Maximized:', maximized);
});
// 窗口最小化状态改变
await window.onMinimized(({ payload: minimized }) => {
console.log('Minimized:', minimized);
});
6.2 后端窗口事件 #
rust
use tauri::Manager;
tauri::Builder::default()
.setup(|app| {
let window = app.get_webview_window("main").unwrap();
// 监听窗口关闭
window.on_window_event(move |event| {
match event {
tauri::WindowEvent::CloseRequested { .. } => {
println!("Window close requested");
}
tauri::WindowEvent::Destroyed => {
println!("Window destroyed");
}
tauri::WindowEvent::Focused(focused) => {
println!("Window focused: {}", focused);
}
_ => {}
}
});
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
七、窗口数据传递 #
7.1 创建时传递数据 #
typescript
import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
const window = new WebviewWindow('detail', {
url: 'detail.html',
title: 'Detail',
width: 600,
height: 400,
});
// 发送数据到新窗口
window.once('tauri://created', async () => {
await window.emit('init-data', {
id: 123,
name: 'Item Name',
});
});
typescript
// 在新窗口中接收数据
import { listen } from '@tauri-apps/api/event';
await listen('init-data', (event) => {
const data = event.payload;
console.log('Received init data:', data);
});
7.2 通过 URL 参数传递 #
typescript
const params = new URLSearchParams({
id: '123',
name: 'Item Name',
});
const window = new WebviewWindow('detail', {
url: `detail.html?${params.toString()}`,
title: 'Detail',
width: 600,
height: 400,
});
typescript
// 在新窗口中解析参数
const params = new URLSearchParams(window.location.search);
const id = params.get('id');
const name = params.get('name');
八、窗口状态 #
8.1 获取窗口状态 #
typescript
import { getCurrentWindow } from '@tauri-apps/api/window';
const window = getCurrentWindow();
// 获取标题
const title = await window.title();
// 获取大小
const size = await window.innerSize();
console.log('Size:', size.width, size.height);
// 获取位置
const position = await window.outerPosition();
console.log('Position:', position.x, position.y);
// 获取状态
const isMaximized = await window.isMaximized();
const isMinimized = await window.isMinimized();
const isFullscreen = await window.isFullscreen();
const isFocused = await window.isFocused();
const isVisible = await window.isVisible();
const isDecorated = await window.isDecorated();
const isResizable = await window.isResizable();
8.2 监控窗口状态 #
typescript
import { useEffect, useState } from 'react';
import { getCurrentWindow } from '@tauri-apps/api/window';
export function useWindowState() {
const window = getCurrentWindow();
const [isMaximized, setIsMaximized] = useState(false);
useEffect(() => {
window.isMaximized().then(setIsMaximized);
const unlisten = window.onMaximized(({ payload }) => {
setIsMaximized(payload);
});
return () => {
unlisten.then((fn) => fn());
};
}, []);
return isMaximized;
}
九、最佳实践 #
9.1 窗口管理器 #
typescript
// WindowManager.ts
import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
class WindowManager {
private windows: Map<string, WebviewWindow> = new Map();
async create(label: string, options: WindowOptions) {
if (this.windows.has(label)) {
const existing = this.windows.get(label)!;
await existing.setFocus();
return existing;
}
const window = new WebviewWindow(label, options);
this.windows.set(label, window);
window.once('tauri://destroyed', () => {
this.windows.delete(label);
});
return window;
}
async close(label: string) {
const window = this.windows.get(label);
if (window) {
await window.close();
this.windows.delete(label);
}
}
async closeAll() {
for (const [label] of this.windows) {
await this.close(label);
}
}
}
export const windowManager = new WindowManager();
9.2 单例窗口 #
typescript
async function openSettingsWindow() {
const existing = await WebviewWindow.getByLabel('settings');
if (existing) {
await existing.setFocus();
return existing;
}
return new WebviewWindow('settings', {
url: 'settings.html',
title: 'Settings',
width: 500,
height: 400,
});
}
十、调试技巧 #
10.1 打开开发者工具 #
typescript
import { getCurrentWindow } from '@tauri-apps/api/window';
const window = getCurrentWindow();
// 打开开发者工具
await window.openDevTools();
// 关闭开发者工具
await window.closeDevTools();
// 判断是否打开
const isOpen = await window.isDevToolsOpen();
10.2 窗口信息日志 #
typescript
async function logWindowInfo() {
const window = getCurrentWindow();
console.log('Window Info:', {
label: window.label,
title: await window.title(),
size: await window.innerSize(),
position: await window.outerPosition(),
isMaximized: await window.isMaximized(),
isMinimized: await window.isMinimized(),
isFullscreen: await window.isFullscreen(),
});
}
十一、总结 #
11.1 核心要点 #
| 要点 | 说明 |
|---|---|
| 配置创建 | 在 tauri.conf.json 中定义 |
| 动态创建 | 使用 WebviewWindowBuilder |
| 窗口属性 | 通过 API 设置和获取 |
| 生命周期 | 监听各种窗口事件 |
| 数据传递 | 通过事件或 URL 参数 |
11.2 下一步 #
现在你已经掌握了窗口创建,接下来让我们学习 窗口配置,深入了解窗口的各种配置选项!
最后更新:2026-03-28