在Electron-Vue中实现macOS风格自定义标题栏

embedded/2025/3/17 18:51:40/

在Electron-Vue中实现macOS风格自定义标题栏

在Electron应用开发中,自定义标题栏是实现个性化界面设计的重要环节。本文将介绍如何在electron-vue项目中实现macOS风格的自定义标题栏,包含窗口控制、状态同步和样式优化等关键功能。

一. 核心实现步骤

1. 主进程配置

在创建BrowserWindow时关闭默认框架:

// main.js
function createWindow() {const mainWindow = new BrowserWindow({frame: false,titleBarStyle: "hidden",//其他配置});// 监听窗口最大化状态变化mainWindow.on("maximize", () => {mainWindow.webContents.send("window-maximized", true);});mainWindow.on("unmaximize", () => {mainWindow.webContents.send("window-maximized", false);});// 处理窗口操作的IPC消息ipcMain.on("window-minimize", () => {mainWindow.minimize();});ipcMain.on("window-maximize", () => {if (mainWindow.isMaximized()) {mainWindow.unmaximize();} else {mainWindow.maximize();}});ipcMain.on("window-close", () => {mainWindow.close();});ipcMain.handle("window-is-maximized", () => {return mainWindow.isMaximized();});//其他配置
}

窗口状态事件监听:

mainWindow.on("maximize", () => {mainWindow.webContents.send("window-maximized", true);
});mainWindow.on("unmaximize", () => {mainWindow.webContents.send("window-maximized", false);
});
2. 预加载脚本通信

暴露安全的窗口控制API:

// preload.js
const windowAPI = {minimize: () => ipcRenderer.send('window-minimize'),maximize: () => ipcRenderer.send('window-maximize'),close: () => ipcRenderer.send('window-close'),onMaximizeChange: (callback) => {ipcRenderer.on('window-maximized', (_, isMaximized) => callback(isMaximized))}
}if (process.contextIsolated) {try {contextBridge.exposeInMainWorld('electron', {...electronAPI,window: windowAPI})contextBridge.exposeInMainWorld('api', api)} catch (error) {console.error(error)}
} else {window.electron = {...electronAPI,window: windowAPI}window.api = api
}
3. 自定义标题栏组件
模板结构
<template><div class="titlebar" :class="{ 'is-maximized': isMaximized }"><el-row class="titlebar-row"><el-col :span="16" class="title-col"><div class="window-title">{{ title }}</div></el-col><el-col :span="4" class="control-col"><div class="window-controls"><button @click="minimize"></button><button @click="toggleMaximize"></button><button @click="close"></button></div></el-col></el-row></div>
</template>
核心逻辑
export default {data() {return { isMaximized: false }},mounted() {window.electron.window.onMaximizeChange((isMax) => {this.isMaximized = isMax})this.$el.addEventListener('dblclick', this.handleDoubleClick)},methods: {minimize() {window.electron.window.minimize()},toggleMaximize() {window.electron.window.maximize()},handleDoubleClick(e) {if (!e.target.closest('.window-controls')) {this.toggleMaximize()}}}
}
关键样式
.titlebar {height: 30px;-webkit-app-region: drag; /* 可拖拽区域 */
}.window-controls {-webkit-app-region: no-drag; /* 非拖拽区域 */
}.control-button {width: 16px;height: 16px;border-radius: 50%;transition: all 0.2s ease;
}/* macOS风格按钮配色 */
.minimize { background-color: #ffbd2e; }
.maximize { background-color: #28c940; }
.close { background-color: #ff5f57; }

二. TitleBar完整代码

<template><divclass="titlebar":class="{ 'is-maximized': isMaximized }"data-platform="darwin"><el-row :gutter="0" class="titlebar-row"><el-col :span="4" class="left-col"></el-col><el-col :span="16" class="title-col"><div class="window-title">{{ title }}</div></el-col><el-col :span="4" class="control-col"><div class="window-controls" @dblclick.stop><!-- 按钮顺序调整为:最小化、最大化、关闭 --><button class="control-button minimize" @click="minimize"></button><buttonclass="control-button maximize":class="{ restored: isMaximized }"@click="toggleMaximize"></button><button class="control-button close" @click="close"></button></div></el-col></el-row></div>
</template><script>
export default {name: 'TitleBar',props: {title: {type: String,default: 'Electron App'}},data() {return {platform: window.api.platform,isMaximized: false}},mounted() {window.electron.window.onMaximizeChange((isMaximized) => {this.isMaximized = isMaximized})// 添加双击标题栏最大化/还原的功能this.$el.addEventListener('dblclick', this.handleDoubleClick)},beforeUnmount() {this.$el.removeEventListener('dblclick', this.handleDoubleClick)},methods: {minimize() {window.electron.window.minimize()},toggleMaximize() {window.electron.window.maximize()},close() {window.electron.window.close()},handleDoubleClick(event) {// 确保双击的是标题栏区域,而不是控制按钮if (!event.target.closest('.window-controls')) {this.toggleMaximize()}}}
}
</script><style scoped>
.titlebar {height: 30px;background-color: #f1f1f1;user-select: none;-webkit-app-region: drag;width: 100%;
}.titlebar-row {height: 100%;margin: 0 !important;
}.control-col, .title-col, .left-col {height: 100%;display: flex;align-items: center;
}.title-col {justify-content: center;
}.window-title {font-size: 14px;font-weight: 500;color: #333;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;line-height: 30px;
}.window-controls {display: flex;align-items: center;justify-content: flex-end; /* 按钮靠右对齐 */-webkit-app-region: no-drag;height: 100%;padding-right: 12px;
}.control-col {justify-content: flex-end;
}.control-button {width: 16px; /* 增大按钮尺寸 */height: 16px;margin: 0 6px;border-radius: 50%;border: none;cursor: pointer;position: relative;transition: all 0.2s ease;
}/* macOS 风格按钮颜色 */
.control-button.minimize {background-color: #ffbd2e;
}
.control-button.minimize:hover {background-color: #ffcd45;transform: scale(1.1);
}.control-button.maximize {background-color: #28c940;
}
.control-button.maximize:hover {background-color: #3dd958;transform: scale(1.1);
}.control-button.close {background-color: #ff5f57;
}
.control-button.close:hover {background-color: #ff7b72;transform: scale(1.1);
}
</style>

http://www.ppmy.cn/embedded/173397.html

相关文章

防止手机验证码被刷:React + TypeScript 与 Node.js + Express 的全面防御策略

防止手机验证码被刷是开发中常见的安全问题&#xff0c;尤其是在涉及用户注册、登录或敏感操作时。攻击者可能会通过自动化脚本频繁请求验证码&#xff0c;导致短信轰炸或资源浪费。以下是如何在 React TypeScript 前端和 Node.js Express 后端中防止验证码被刷的深度分析&am…

游戏引擎学习第160天

回顾和今天的计划 我们没有使用任何游戏引擎和库&#xff0c;完全靠我们自己&#xff0c;使用的是老式的编程方式。 我们已经构建了很多内容&#xff0c;游戏引擎开发也慢慢接近尾声。现在我们已经接近完成了所有为支持游戏开发所需要的工作&#xff0c;接下来将逐步过渡到游戏…

git使用指南

git使用指南 工作中常用的 Git 命令&#xff0c;这些基本够用了。能够记住命令的话可以使你的工作效率提高一大截&#xff0c;当然使用可视化的代码编译工具操作也可。管他操作是否高大上&#xff0c;适合你的才是最好的&#xff01; 1. 克隆远程仓库的代码到本地 git clone g…

HTTP 和 HTTPS:从不安全到安全的蜕变之路

HTTP&#xff08;超文本传输协议&#xff09;和 HTTPS&#xff08;超文本传输安全协议&#xff09;是网络上最常用的协议&#xff0c;它们为网页浏览、数据传输提供基础支持。虽然只有一字之差&#xff0c;但 HTTPS 却对 HTTP 做出了巨大的改进&#xff0c;尤其在安全性方面。本…

java泛型通配符?及上下界(extends,super)保证安全性、灵活性、可读性

在 Java 中&#xff0c;泛型通配符&#xff08;?&#xff09;用于表示未知类型&#xff0c;通常用于增强泛型的灵活性。通配符可以与上下限结合使用&#xff0c;以限制泛型的范围。以下是通配符及上下限的使用示例&#xff1a; 1. 无界通配符 (?) 无界通配符表示可以接受任意…

前缀和算法第一弹(一维前缀和和二维前缀和)

目录 前言 1. 一维前缀和 &#xff08;1&#xff09;题目及示例 ​编辑 &#xff08;2&#xff09;暴力解法 &#xff08;3&#xff09;算法优化 2. 二维前缀和 &#xff08;1&#xff09;题目及示例 &#xff08;2&#xff09;暴力解法 &#xff08;3&#xff09;算…

vscode接入DeepSeek 免费送2000 万 Tokens 解决DeepSeek无法充值问题

1. 在vscode中安装插件 Cline 2.打开硅基流动官网 3. 注册并登陆&#xff0c;邀请码 WpcqcXMs 4.登录后新建秘钥 5. 在vscode中配置cline (1) API Provider 选择 OpenAI Compatible &#xff1b; (2) Base URL设置为 https://api.siliconflow.cn](https://api.siliconfl…

MySQL时间溢出原理、影响与解决方案

一、问题背景与现象复现 操作场景&#xff1a; 本文将手把手带您了解mysql时间溢出原理、实战影响与全面解决方案&#xff0c;所有代码均通过dblens for mysql数据库工具验证&#xff0c;推荐使用该工具进行可视化数据库管理和开发。 在MySQL 5.7环境中&#xff0c;若通过命令…