在 Tauri 中实现自定义标题栏和窗口拖拽并不复杂,核心思路是:隐藏系统原生标题栏,用前端元素模拟标题栏,并通过 Tauri 提供的拖拽区域属性让用户能拖动窗口。
1. 隐藏原生标题栏
在 tauri.conf.json 中,为需要自定义标题栏的窗口关闭装饰(decorations):
{
"app": {
"windows": [
{
"title": "My App",
"width": 800,
"height": 600,
"decorations": false
}
]
}
}
这样窗口就没有了系统自带的标题栏、最小化/最大化/关闭按钮。剩下的空白区域你可以用 HTML/CSS 全部接管。
2. 前端实现拖拽区域
Tauri 提供了一个特殊的 data-tauri-drag-region 属性,把它加到任意 HTML 元素上,该元素就会变成一个可拖拽的区域(类似于标题栏的作用)。在自定义标题栏的 div 上加上这个属性即可:
<div data-tauri-drag-region class="titlebar">
<span>我的应用</span>
<div class="window-controls">
<button id="minimize">—</button>
<button id="maximize">□</button>
<button id="close">✕</button>
</div>
</div>
配合 CSS,你可以把它固定在窗口顶部,并设置样式:
.titlebar {
height: 36px;
background: #2c2c2c;
display: flex;
align-items: center;
padding: 0 12px;
user-select: none;
}
这样整个 titlebar 区域都可以拖拽,但它的子元素(比如按钮)通常不响应拖拽,因为按钮默认会捕获鼠标事件。如果你希望标题栏上的文字或图标也能拖动,不需要额外处理;但按钮需要正常点击,所以 Tauri 会智能判断:在 data-tauri-drag-region 内,鼠标事件会传递给子元素,如果子元素是可交互的(按钮、输入框等),拖拽会被忽略,操作正常生效。
3. 实现窗口控制按钮
关闭、最小化、最大化按钮需要用 JavaScript 调用 Tauri 的窗口 API。首先确保已安装 @tauri-apps/api:
npm install @tauri-apps/api
然后在对应的按钮事件中调用:
import { getCurrentWindow } from '@tauri-apps/api/window';
const currentWindow = getCurrentWindow();
document.getElementById('minimize').addEventListener('click', () => {
currentWindow.minimize();
});
document.getElementById('maximize').addEventListener('click', async () => {
const isMaximized = await currentWindow.isMaximized();
if (isMaximized) {
currentWindow.unmaximize();
} else {
currentWindow.maximize();
}
});
document.getElementById('close').addEventListener('click', () => {
currentWindow.close();
});
4. 注意事项
- 双击最大化:如果你的自定义标题栏需要支持双击最大化,可以手动监听双击事件并调用
toggleMaximize()或手动判断状态后切换。 - 右键系统菜单:原生标题栏右键会弹出系统菜单(还原/移动/大小等)。如果想保留,可以在标题栏区域监听
contextmenu事件,调用 Tauri 的showWindowMenu(需要 Tauri 2.x 或自行实现菜单)。 - 拖拽区域与其他交互冲突:如果拖拽区域内有一些需要拖拽的自定义元素(比如滑块),可能会产生冲突。此时可给那些元素添加
data-tauri-drag-region="false"来排除。 - 边框阴影和圆角:关闭原生装饰后,窗口可能失去系统自带的阴影。你可以用 CSS 的
box-shadow或border-radius在窗口根元素上模拟,但注意 macOS 的窗口圆角还需要配合隐藏装饰时的透明边框调整。 - 性能:由于所有拖拽逻辑由 Tauri 底层处理,前端无需手动计算坐标,所以响应迅速且无卡顿。
一句话总结
通过 decorations: false 隐藏原生标题栏,用 data-tauri-drag-region 实现拖拽,再调用窗口 API 完成控制按钮,就能轻松打造出美观且实用的自定义标题栏。整个过程无需修改 Rust 代码,全部在前端完成。