在 Electron-Vite (一)快速构建桌面应用 中我们讲解了怎么快速构建一个Electron应用,并且怎么在主进程和渲染进程之间进行通信
那在本章节中,我们重点讲解一下怎么自定义Electron的标题栏
相信大多数开发过Electron应用的工程师都会抛弃原有的标题栏,原生的标题栏无法高度自定义,所以我们在构建的过程中,就要隐藏掉原生的,自己设计开发符合要求的标题栏
那接下来我们开始
第一步:隐藏原生标题栏
我们来看下面这张图,如图所示,这是原生的Electron的标题栏
接下来我们先隐藏原生的标题栏
我们来到主进程下面的index.ts文件
然后mainWindow的配置内容修改如下
// Create the browser window.
mainWindow = new BrowserWindow({
width: 900,
height: 670,
show: false,
autoHideMenuBar: true,
//隐藏标题栏
frame: false,
titleBarStyle: 'hidden',
...(process.platform === 'linux' ? { icon } : {}),
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false
}
})
然后我们重启项目,就会发现标题栏消失了
第二步:设计标题栏页面
我们先回到渲染进程里面的App.vue文件里面
将代码改成下面样子
<template>
<div class="title-container"></div>
</template>
<script setup lang="ts"></script>
<style>
body {
margin: 0;
padding: 0;
}
.title-container {
width: 100%;
height: 30px;
background-color: rgb(226, 241, 255);
-webkit-app-region: drag; /* 允许拖拽 */
}
</style>
然后我们运行项目后,页面就会呈现现在的样子
鼠标在蓝色的标头区域,可以进行拖动,双击也可以进行放大缩小
然后我们 给我们的标题栏填充一些内容
<template>
<div class="title-container">
<div class="left">
<span>软件Icon</span>
</div>
<div class="right">
<div class="btn-item">隐藏</div>
<div class="btn-item">放大</div>
<div class="btn-item">关闭</div>
</div>
</div>
</template>
<script setup lang="ts"></script>
<style>
body {
margin: 0;
padding: 0;
}
.title-container {
width: 100%;
height: 30px;
background-color: rgb(226, 241, 255);
-webkit-app-region: drag; /* 允许拖拽 */
display: flex;
justify-content: space-between;
}
.right {
display: flex;
justify-content: right;
-webkit-app-region: no-drag;
gap: 10px;
}
.btn-item {
cursor: pointer;
}
</style>
效果展示
这时我们就会发现只有放大按钮,没有缩小按钮,这时我们就有一个疑问,放大和缩小按钮是谁来控制,当我们软件最大化后,我们怎么知道软件已经最大化了,反之,我们又怎么知道软件最小化了
第三步:最大化和最小化按钮的切换
让我们回到主进程的index.ts里面
在这里加一段代码
//监听窗口尺寸
mainWindow.on('resize', () => {
const isMax = mainWindow.isMaximized()
if (isMax) {
mainWindow.webContents.send('winSizeChange', { size: 'max' })
} else {
mainWindow.webContents.send('winSizeChange', { size: 'min' })
}
})
这段代码的意思是我们要开始监听mainWindow窗口的尺寸,如果窗口发生了改变,就会立即触发回调函数
isMaximized()方法就是能够判断当前窗口是否是最大化
mainWindow.webContents.send('winSizeChange', { size: 'max' }),这一段代码是主进程向渲染进程发消息,通知我的窗口已发生了变化,并把当前窗口的尺寸大小传过去
然后我们再次回到App.vue里面
将内容修改成下面样子
<template>
<div class="title-container">
<div class="left">
<span>软件Icon</span>
</div>
<div class="right">
<div class="btn-item">隐藏</div>
<div v-if="sizeType === 'min'" class="btn-item">放大</div>
<div v-if="sizeType === 'max'" class="btn-item">缩小</div>
<div class="btn-item">关闭</div>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
//当前窗口尺寸的类型
const sizeType = ref<'max' | 'min'>('min')
onMounted(() => {
window.electron.ipcRenderer.on('winSizeChange', (event, type) => {
sizeType.value = type.size
})
})
</script>
<style>
body {
margin: 0;
padding: 0;
}
.title-container {
width: 100%;
height: 30px;
background-color: rgb(226, 241, 255);
-webkit-app-region: drag; /* 允许拖拽 */
display: flex;
justify-content: space-between;
}
.right {
display: flex;
justify-content: right;
-webkit-app-region: no-drag;
gap: 10px;
}
.btn-item {
cursor: pointer;
}
</style>
我们再来看界面
没有占满屏幕时
占满屏幕后
第四步:串接功能
还是在App.vue里面,代码如下
<template>
<div class="title-container">
<div class="left">
<span>软件Icon</span>
</div>
<div class="right">
<div class="btn-item" @click="handleClick('hide')">隐藏</div>
<div v-if="sizeType === 'min'" class="btn-item" @click="handleClick('max')">放大</div>
<div v-if="sizeType === 'max'" class="btn-item" @click="handleClick('min')">缩小</div>
<div class="btn-item" @click="handleClick('close')">关闭</div>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
//当前窗口尺寸的类型
const sizeType = ref<'max' | 'min'>('min')
onMounted(() => {
window.electron.ipcRenderer.on('winSizeChange', (event, type) => {
sizeType.value = type.size
})
})
const handleClick = (type: 'hide' | 'min' | 'max' | 'close'): void => {
window.electron.ipcRenderer.send('winAction', { type })
}
</script>
<style>
body {
margin: 0;
padding: 0;
}
.title-container {
width: 100%;
height: 30px;
background-color: rgb(226, 241, 255);
-webkit-app-region: drag; /* 允许拖拽 */
display: flex;
justify-content: space-between;
}
.right {
display: flex;
justify-content: right;
-webkit-app-region: no-drag;
gap: 10px;
}
.btn-item {
cursor: pointer;
}
</style>
四个功能按钮经过click事件,向主进程发送消息,消息窗口是winAction,主进程监听这个消息窗口用来获取消息内容,然后再判断type类型
然后我们回到monitorEvent.ts里面
代码效果如下
import { ipcMain } from 'electron'
import { mainWindow } from '.'
export const monitorEvent = (): void => {
ipcMain.on('toMain', (e, data) => {
console.log(data)
})
ipcMain.on('winAction', (e, data) => {
const type = data.type
if (type === 'hide') {
//最小化窗口
mainWindow.minimize()
} else if (type === 'min') {
//取消最大化
mainWindow.unmaximize()
} else if (type === 'max') {
//最大化
mainWindow.maximize()
} else if (type === 'close') {
//关闭窗口
mainWindow.close()
}
})
}
最后运行项目,就会发现标题栏的功能都完整齐全了