Tauri自定义标题栏集成原生系统按钮实现方案咨询
实现Tauri自定义标题栏(支持Windows/macOS + NextJS)
第一步:配置Tauri窗口
在src-tauri/tauri.conf.json中禁用默认标题栏,同时开启窗口控制权限:
{ "tauri": { "windows": [ { "title": "你的应用", "width": 800, "height": 600, "decorations": false, // 关闭默认标题栏装饰 "titleBarStyle": "hidden", // macOS下隐藏原生标题栏 "hiddenTitle": true // Windows下隐藏标题文字 } ], "allowlist": { "window": { "minimize": true, "maximize": true, "close": true, "startDragging": true } } } }
第二步:前端(NextJS)构建自定义标题栏
创建组件区分Windows和macOS的布局差异,实现拖拽和系统按钮功能:
// components/CustomTitleBar.tsx 'use client' import { useEffect, useState } from 'react' import { invoke } from '@tauri-apps/api/tauri' import { window } from '@tauri-apps/api' export default function CustomTitleBar() { const [isMacOS, setIsMacOS] = useState(false) const [isMaximized, setIsMaximized] = useState(false) useEffect(() => { // 获取当前系统类型 invoke('get_os').then(os => setIsMacOS(os === 'macos')) // 监听窗口最大化状态 const currentWindow = window.getCurrentWindow() currentWindow.on('maximize', () => setIsMaximized(true)) currentWindow.on('unmaximize', () => setIsMaximized(false)) }, []) // 系统按钮操作函数 const handleMinimize = () => window.getCurrentWindow().minimize() const handleMaximize = () => { const win = window.getCurrentWindow() isMaximized ? win.unmaximize() : win.maximize() } const handleClose = () => window.getCurrentWindow().close() const handleDrag = () => window.getCurrentWindow().startDragging() return ( <div className={`h-12 flex items-center ${isMacOS ? 'justify-between px-6' : 'justify-between px-4 bg-gray-800'}`} onMouseDown={handleDrag} > {/* 左侧自定义菜单按钮 */} <div className="flex items-center gap-4"> <button className="text-white hover:text-gray-300">菜单</button> <span className="text-white font-medium">你的应用</span> </div> {/* 右侧系统按钮组 */} <div className="flex items-center gap-2"> {isMacOS ? ( <> <button onClick={handleMinimize} className="w-8 h-8 rounded-full hover:bg-gray-700 flex items-center justify-center text-white"> <svg width="12" height="12" fill="currentColor"><path d="M6 10C6.552 10 7 9.552 7 9V3C7 2.448 6.552 2 6 2S5 2.448 5 3V9C5 9.552 5.448 10 6 10Z"/></svg> </button> <button onClick={handleMaximize} className="w-8 h-8 rounded-full hover:bg-gray-700 flex items-center justify-center text-white"> {isMaximized ? <svg width="12" height="12" fill="currentColor"><path d="M3 3V5H5V3H3ZM3 7V9H5V7H3ZM7 3V5H9V3H7ZM7 7V9H9V7H7Z"/></svg> : <svg width="12" height="12" fill="currentColor"><path d="M3 3H5V5H3V3ZM7 3H9V5H7V3ZM3 7H5V9H3V7ZM7 7H9V9H7V7Z"/></svg> } </button> <button onClick={handleClose} className="w-8 h-8 rounded-full hover:bg-red-600 flex items-center justify-center text-white"> <svg width="12" height="12" fill="currentColor"><path d="M3.293 3.293C3.683 2.902 4.317 2.902 4.707 3.293L6 4.586L7.293 3.293C7.683 2.902 8.317 2.902 8.707 3.293C9.098 3.683 9.098 4.317 8.707 4.707L7.414 6L8.707 7.293C9.098 7.683 9.098 8.317 8.707 8.707C8.317 9.098 7.683 9.098 7.293 8.707L6 7.414L4.707 8.707C4.317 9.098 3.683 9.098 3.293 8.707C2.902 8.317 2.902 7.683 3.293 7.293L4.586 6L3.293 4.707C2.902 4.317 2.902 3.683 3.293 3.293Z"/></svg> </button> </> ) : ( <> <button onClick={handleMinimize} className="w-10 h-10 hover:bg-gray-700 flex items-center justify-center text-white"> <svg width="10" height="2" fill="currentColor"><rect width="10" height="2" rx="1"/></svg> </button> <button onClick={handleMaximize} className="w-10 h-10 hover:bg-gray-700 flex items-center justify-center text-white"> {isMaximized ? <svg width="10" height="10" fill="currentColor"><path d="M2 2V4H4V2H2ZM2 6V8H4V6H2ZM6 2V4H8V2H6ZM6 6V8H8V6H6Z"/></svg> : <svg width="10" height="10" fill="none" stroke="currentColor" strokeWidth="2"><path d="M0 2H2V0H8V2H10V8H8V10H2V8H0V2Z"/></svg> } </button> <button onClick={handleClose} className="w-10 h-10 hover:bg-red-600 flex items-center justify-center text-white"> <svg width="10" height="10" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M1 1L9 9M9 1L1 9"/></svg> </button> </> )} </div> </div> ) }
第三步:Rust后端添加系统判断命令
在src-tauri/src/main.rs中实现获取当前系统的逻辑:
use tauri::{command, Runtime}; #[command] fn get_os() -> String { #[cfg(target_os = "macos")] return "macos".to_string(); #[cfg(target_os = "windows")] return "windows".to_string(); #[cfg(target_os = "linux")] return "linux".to_string(); } fn main() { tauri::Builder::default() .invoke_handler(tauri::generate_handler![get_os]) .run(tauri::generate_context!()) .expect("运行Tauri应用出错"); }
第四步:在NextJS页面中使用标题栏
在主页面引入自定义标题栏组件:
// app/page.tsx import CustomTitleBar from '@/components/CustomTitleBar' export default function Home() { return ( <div className="h-screen flex flex-col"> <CustomTitleBar /> <div className="flex-1 p-4"> <h1 className="text-2xl font-bold">自定义标题栏演示</h1> </div> </div> ) }
跨平台细节注意
- macOS:标题栏拖拽通过
startDragging实现,系统按钮样式遵循圆角设计,窗口圆角由Tauri自动处理 - Windows:需给标题栏设置背景色区分内容区,实时监听窗口最大化状态切换按钮图标
- 确保安装依赖:
npm install @tauri-apps/api,使用npm run tauri dev启动测试
内容的提问来源于stack exchange,提问作者thelittlemaster
相关产品推荐
相关产品推荐

