在开发 Electron 应用的时候,通常会将自带的"窗口控制按钮区域" 隐藏, 然后自己实现对窗口的控制。
下图是在 mac 下面的效果。
首先用HTML和CSS创建窗口控制按钮
以下例子会展示了如何使用CSS的伪元素,过渡,以及其他技术来创建出非常独特的、具有交互感的窗口控制按钮。
基本结构
首先,我们需要构建HTML的基本结构。每个按钮都包含在<div>
标签内,并且都有一个btn
类,以及各自特有的类(例如close-btn
、min-btn
或max-btn
)。这就让我们能够在CSS中针对性地进行样式修改。
<div class="wrapper">
<div class="btn close-btn"></div>
<div class="btn min-btn"></div>
<div class="btn max-btn"></div>
</div>
CSS样式
接着,我们用CSS为每个按钮添加样式。所有按钮都有一些共享的样式,例如宽度、高度和边界半径等。每个按钮还有自己的背景颜色和边界颜色。
.btn {
width: 12px;
height: 12px;
border-radius: 50%;
margin-right: 6px;
position: relative;
overflow: hidden;
cursor: pointer;
}
.close-btn {
background: #FF5D5B;
border: 1px solid #CF544D;
}
.min-btn {
background: #FFBB39;
border: 1px solid #CFA64E;
}
.max-btn {
background: #00CD4E;
border: 1px solid #0EA642;
}
利用伪元素添加图标
然后,我们利用伪元素为按钮添加图标。::before
和::after
伪元素在按钮内创建了两个额外的元素,我们可以利用这些元素创建按钮的图标。例如,关闭按钮的图标是一个红色的“X”,最小化按钮的图标是一个黄色的“-”,最大化按钮的图标是一个绿色的“+”。
/* Close btn */
.close-btn:before, .close-btn:after {
width: 1px;
height: 70%;
background: #460100;
}
.close-btn:before {
transform: translate(-50%, -50%) rotate(45deg);
}
.close-btn:after {
transform: translate(-50%, -50%) rotate(-45deg);
}
/* min btn */
.min-btn:before {
width: 70%;
height: 1px;
background: #460100;
}
/* max btn */
.max-btn:before {
width: 50%;
height: 50%;
background: #024
代码演示
为了方便,我将这部分代码放到一个页面上了
点击这里 可以查看,全部源码可以在 chrome 的控制台看到。
将上面的代码用在 electron +vue3 中
先上代码,实现一个组件,这个组件实现了最大化、最小化、关闭等事件。
<script setup lang="ts">
import { onMounted, ref, onUnmounted } from "vue";
import { ipcRenderer } from "electron";
defineProps<{ title?: strng }>();
let hover = ref('');
//关闭窗口
let closeWindow = () => {
ipcRenderer.invoke("closeWindow");
};
//最大化窗口
let maxmizeMainWin = () => {
ipcRenderer.invoke("maxmizeWindow");
};
//最小化窗口
let minimizeMainWindow = () => {
ipcRenderer.invoke("minimizeWindow");
};
//窗口最大化事件
let winMaximizeEvent = () => {
console.log('max')
};
onMounted(() => {
ipcRenderer.on("windowMaximized", winMaximizeEvent);
});
onUnmounted(() => {
ipcRenderer.off("windowMaximized", winMaximizeEvent);
});
</script>
<template>
<div class="wrapper">
<div class="btn close-btn" @click="closeWindow" @mouseover="hover = 'close'" @mouseleave="hover = ''"></div>
<div class="btn min-btn" @click="minimizeMainWindow" @mouseover="hover = 'min'" @mouseleave="hover = ''"></div>
<div class="btn max-btn" @click="maxmizeMainWin" @mouseover="hover = 'max'" @mouseleave="hover = ''"></div>
</div>
</template>
<style scoped>
body {
margin: 0;
}
.wrapper {
height: 32px;
background: rgb(46, 46, 46);
display: flex;
justify-content: center;
align-items: center;
}
.btn {
width: 12px;
height: 12px;
border-radius: 50%;
margin-right: 6px;
position: relative;
overflow: hidden;
cursor: pointer;
}
.btn:last-child {
margin-right: 0;
}
.btn:before,
.btn:after {
content: "";
position: absolute;
top: 100%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 1px;
opacity: 0;
transition: all 300ms ease-in-out;
}
.close-btn {
background: #FF5D5B;
border: 1px solid #CF544D;
}
.min-btn {
background: #FFBB39;
border: 1px solid #CFA64E;
}
.max-btn {
background: #00CD4E;
border: 1px solid #0EA642;
}
/* Close btn */
.close-btn:before,
.close-btn:after {
width: 1px;
height: 70%;
background: #460100;
}
.close-btn:before {
transform: translate(-50%, -50%) rotate(45deg);
}
.close-btn:after {
transform: translate(-50%, -50%) rotate(-45deg);
}
/* min btn */
.min-btn:before {
width: 70%;
height: 1px;
background: #460100;
}
/* max btn */
.max-btn:before {
width: 50%;
height: 50%;
background: #024D0F;
}
.max-btn:after {
width: 1px;
height: 90%;
transform: translate(-50%, -50%) rotate(-135deg);
background: #00CD4E;
}
/* Hover function */
.wrapper:hover .btn:before,
.wrapper:hover .btn:after {
top: 50%;
opacity: 1;
}
</style>
其中closeWindow
,maxmizeWindow
, minimizeWindow
等还需要在主进程注册, 可以参考下面代码。
ipcMain.handle("minimizeWindow", (e) => {
this.getWin(e)?.minimize();
});
ipcMain.handle("maxmizeWindow", (e) => {
const win = BrowserWindow.getFocusedWindow();
if(win) {
if (process.platform === 'darwin') {
this.getWin(e)?.setFullScreen(true);
} else {
this.getWin(e)?.maximize();
}
}
});
ipcMain.handle("unmaximizeWindow", (e) => {
const win = BrowserWindow.getFocusedWindow();
if(win) {
if (process.platform === 'darwin') {
this.getWin(e)?.setFullScreen(false);
} else {
this.getWin(e)?.unmaximize();
}
}
});
当最大化的时候,可以隐藏,调用原生的窗口控制按钮。这样就不用实现如下的效果了。
监听窗口最大化事件,用v-if
即可实现,在此不再过多赘述。
发表回复