vue?electron實(shí)現(xiàn)無(wú)邊框窗口示例詳解
一、前言
無(wú)邊框窗口是不帶外殼(包括窗口邊框、工具欄等),只含有網(wǎng)頁(yè)內(nèi)容的窗口。對(duì)于一個(gè)產(chǎn)品來(lái)講,桌面應(yīng)用帶邊框的很少,因?yàn)槌螅ㄎ覀兊腢I覺(jué)得--與我無(wú)關(guān)-.-)。因此我們就來(lái)展開(kāi)說(shuō)下,在做無(wú)邊框窗口時(shí)候需要注意的事項(xiàng)以及我踩過(guò)的坑。
二、實(shí)現(xiàn)方案
1.創(chuàng)建無(wú)邊框窗口
要?jiǎng)?chuàng)建無(wú)邊框窗口,只需在 BrowserWindow 的 options 中將 frame 設(shè)置為 false:
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({
width: 800,
height: 600,
// 設(shè)置為 `false` 時(shí)可以創(chuàng)建一個(gè)無(wú)邊框窗口。 默認(rèn)值為 `true`
frame: false,
// 無(wú)標(biāo)題時(shí),在mac內(nèi),窗口將一直擁有位于左上的標(biāo)準(zhǔn)窗口控制器 (“traffic lights”)
titleBarStyle: 'hidden',
// mac設(shè)置控制按鈕在無(wú)邊框窗口中的位置。
trafficLightPosition: { x: 12, y: 18 },
// 在windows上,設(shè)置默認(rèn)顯示窗口控制工具
titleBarOverlay: { color: "#fff", symbolColor: "black", }
})
win.show()
在electron官網(wǎng)中有這么一段描述
titleBarStyle String (可選) macOS Windows - 窗口標(biāo)題欄樣式。 默認(rèn)值為 default. 可能的值有
hidden- 在一個(gè)隱藏的標(biāo)題欄和一個(gè)全尺寸大小的內(nèi)容窗口中取得結(jié)果。 在 macOS 內(nèi), 窗口將一直擁有位于左上的標(biāo)準(zhǔn)窗口控制器 (“traffic lights”)。- 在 Windows上,當(dāng)與
titleBarOverlay: true合并時(shí),它將激活窗口控件疊加(詳情請(qǐng)參閱titleBarOverlay),否則將不會(huì)顯示窗口控件
titleBarOverlay Object | Boolean (可選) - 當(dāng)使用無(wú)框窗口配置win.setWindowButtonVisibility(true) 在 macOS 或使用 titleBarStyle 可使標(biāo)準(zhǔn)窗口控制可見(jiàn) ("traffic lights" on macOS) ,當(dāng)前屬性開(kāi)啟 Window Controls 覆蓋 JavaScript APIs 和 CSS Environment Variables 指定 true 將導(dǎo)致覆蓋默認(rèn)系統(tǒng)顏色。 默認(rèn)值為 false.
這里說(shuō)兩者配合使用,即titleBarStyle為hidden,并且titleBarOverlay為true或者對(duì)象時(shí),則windows系統(tǒng)中,應(yīng)用窗口也會(huì)默認(rèn)顯示出window操作系統(tǒng)的窗口控件工具。
如圖所示

這樣我們就完成了,electron應(yīng)用的無(wú)邊框窗口。
但是這樣的無(wú)邊框窗口僅能實(shí)現(xiàn)通用的樣式,應(yīng)用頭部總是會(huì)被占用一條高度。并且不支持自定義標(biāo)題欄。若你有自定義標(biāo)題欄,或者嵌入式的windows窗口控件需求,請(qǐng)繼續(xù)往下看
2.創(chuàng)建windows窗口控件組件
因?yàn)槲易龅捻?xiàng)目有windows窗口控件內(nèi)嵌頁(yè)面的需求,而且這樣也方便自定義標(biāo)題欄,所以需要有這樣一個(gè)控件。例如下面這種情況

// WindowsTopControl.vue
<template>
<div class="windows-top-control" :style="{height:mainHeight + 'px'}" :class="{'main-bottom':border}">
<ul class="windows-top-control-win">
<li @click="controlWindow(1)">
<Icon type="最小化圖標(biāo)" />
</li>
<li @click="controlWindow(isFullScreen ? 3 : 2)">
<Icon :type="isFullScreen ? '最大化圖標(biāo)' : '恢復(fù)正常圖標(biāo)'" />
</li>
<li class="close-icon" @click="controlWindow(0)">
<Icon type="關(guān)閉圖標(biāo)" />
</li>
</ul>
</div>
</template>
<script>
import { mapGetters, mapMutations } from 'vuex'
const { ipcRenderer, remote } = require("electron")
const WIN_CONTROL = { // 控件四種操作
0: 'close',
1: 'minimize',
2: 'maximize',
3: 'unmaximize'
}
export default {
name: 'windowsTopControl',
components: {},
props: {
mainHeight: {
type: String,
default: '42'
},
border: {
type: Boolean,
default: false
}
},
computed: { ...mapGetters(['isFullScreen']) },
mounted () {
// 上來(lái)先設(shè)定當(dāng)前窗口是否在最大化的狀態(tài)
this.setIsFullScreen(remote.getCurrentWindow().isMaximized())
// 監(jiān)聽(tīng)是否是最大化窗口 并 更改標(biāo)識(shí)是否最大化
ipcRenderer.on('toggleMax', (e, isFullScreen) => {
this.setIsFullScreen(isFullScreen)
})
},
methods: {
...mapMutations(['setIsFullScreen']),
controlWindow (val) {
// 只有在2、3點(diǎn)擊時(shí),修改是否全屏狀態(tài)
if ([2, 3].includes(val)) {
this.setIsFullScreen(val === 2)
}
remote.getCurrentWindow()[WIN_CONTROL[val]]()
}
},
}
</script>
<style lang="less" scoped>
.windows-top-control {
width: 100%;
height: 42px;
display: flex;
justify-content: flex-end;
.windows-top-control-win {
width: 100%;
height: 24px;
display: flex;
align-items: center;
justify-content: flex-end;
-webkit-app-region: drag;
position: relative;
li {
width: 40px;
height: 100%;
text-align: center;
line-height: 22px;
cursor: pointer;
-webkit-app-region: no-drag;
position: absolute;
pointer-events: auto;
top: -2px;
&:hover {
background: #E0E4E5;
}
&:active {
background: #CDCED0;
}
&:hover {
color: #0183ff;
}
i {
font-size: 14px;
font-weight: 600;
color: #1f2329;
}
}
li:nth-child(1) {
right: 78px;
}
li:nth-child(2) {
right: 38px;
}
li:nth-child(3) {
right: -2px;
}
}
}
.close-icon:hover {
background: #FF6161 !important;
i {
color: #fff !important;
}
}
.close-icon:active {
background: #D64141 !important;
i {
color: #fff !important;
}
}
.main-bottom {
border-bottom: 1px solid #f6f6f6;
}
</style>
下面是vuex中的配置
// selectedState.js
export default {
state: {
// 是否全屏(最大化)
isFullScreen: window.sessionStorage.getItem('isFullScreen') || false,
},
getters: {
isFullScreen: state => state.isFullScreen
},
mutations: {
setIsFullScreen(state, val) {
state.isFullScreen = val
window.sessionStorage.setItem('isFullScreen', val)
}
}
}
接下來(lái) 我們還需在主進(jìn)程中,監(jiān)聽(tīng)用戶的放大、縮小、最小化、關(guān)閉的操作。
// background.js
// win是窗口實(shí)例
win.on('maximize', (event) => {
event.sender.send('toggleMax', true)
})
win.on('unmaximize', (event) => {
event.sender.send('toggleMax', false)
})
準(zhǔn)備工作做完了,接下來(lái)我們就可以來(lái)引用使用組件啦,如下
// home.vue
<template>
<div>
<WindowsTopControl mainHeight="24" />
</div>
</template>
<script>
import WindowsTopControl from './WindowsTopControl.vue'
export default {
components: {
WindowsTopControl
}
}
</script>
以上,我們就完成了自定義的windows控件組就完成了,記得將窗口設(shè)置中的titleBarOverlay注釋掉!這樣我們就能自定義標(biāo)題欄和內(nèi)嵌windows控件了。
三、后記
如果我們自定義控件這種方式實(shí)現(xiàn)的話,還需要考慮一點(diǎn),那就是窗口的拖拽功能,一般情況下,我們拖拽的都是是窗口的頭部。這里我們可以給窗口提前注入一個(gè)js,去創(chuàng)建一個(gè)拖拽條,內(nèi)容如下
// WindowDrag.js
// 在頂部插入一個(gè)的dom
function initTopDrag () {
const topDiv = document.createElement('div') // 創(chuàng)建節(jié)點(diǎn)
topDiv.style.position = 'fixed' // 一直在頂部
topDiv.style.top = '2px'
topDiv.style.left = '2px'
topDiv.style.height = '18px' // 頂部20px才可拖動(dòng)
topDiv.style.width = 'calc(100% - 122px)' // 寬度100%
topDiv.style.zIndex = '9999' // 懸浮于最外層
// topDiv.style.pointerEvents = 'none' // 用于點(diǎn)擊穿透
// @ts-ignore
topDiv.style['-webkit-user-select'] = 'none' // 禁止選擇文字
// @ts-ignore
topDiv.style['-webkit-app-region'] = 'drag' // 拖動(dòng)
topDiv.id = 'drag-top-line'
document.body.appendChild(topDiv) // 添加節(jié)點(diǎn)
}
window.addEventListener('DOMContentLoaded', function onDOMContentLoaded () {
initTopDrag()
document.getElementById('drag-top-line').addEventListener('dblclick', e => {
if (window.$isMac) {
window.ipcRenderer.send('toggleMax')
}
})
})
在創(chuàng)建窗口時(shí)候引入
// background.js
// 這里我將WindowDrag.js文件放在了public種
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: `${__static}/WindowDrag.js`,
}
})
如此我們就完成了拖拽條的設(shè)置。(如圖所示)


以上就是vue electron實(shí)現(xiàn)無(wú)邊框窗口示例詳解的詳細(xì)內(nèi)容,更多關(guān)于vue electron無(wú)邊框窗口的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue3中reactive丟失響應(yīng)式的問(wèn)題解決(避大坑!)
這篇文章主要給大家介紹了關(guān)于Vue3中reactive丟失響應(yīng)式的問(wèn)題解決,vue3中reactive定義的引用類型直接賦值導(dǎo)致數(shù)據(jù)失去響應(yīng)式 ,需要的朋友可以參考下2023-07-07
Vuejs第十一篇組件之slot內(nèi)容分發(fā)實(shí)例詳解
這篇文章主要介紹了Vuejs第十一篇之slot內(nèi)容分發(fā)組件詳解的相關(guān)資料2016-09-09
vue內(nèi)置組件keep-alive事件動(dòng)態(tài)緩存實(shí)例
這篇文章主要介紹了vue內(nèi)置組件keep-alive事件動(dòng)態(tài)緩存實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-10-10
創(chuàng)建Vue項(xiàng)目以及引入Iview的方法示例
這篇文章主要介紹了創(chuàng)建Vue項(xiàng)目以及引入Iview的方法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
vue2模擬vue-element-admin手寫(xiě)角色權(quán)限的實(shí)現(xiàn)
本文主要介紹了vue2模擬vue-element-admin手寫(xiě)角色權(quán)限的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07

