vue electron无边框窗口
做什么梦呢 人气:0一、前言
无边框窗口是不带外壳(包括窗口边框、工具栏等),只含有网页内容的窗口。对于一个产品来讲,桌面应用带边框的很少,因为丑(我们的UI觉得--与我无关-.-)。因此我们就来展开说下,在做无边框窗口时候需要注意的事项以及我踩过的坑。
二、实现方案
1.创建无边框窗口
要创建无边框窗口,只需在 BrowserWindow 的 options
中将 frame
设置为 false
:
const { BrowserWindow } = require('electron') const win = new BrowserWindow({ width: 800, height: 600, // 设置为 `false` 时可以创建一个无边框窗口。 默认值为 `true` frame: false, // 无标题时,在mac内,窗口将一直拥有位于左上的标准窗口控制器 (“traffic lights”) titleBarStyle: 'hidden', // mac设置控制按钮在无边框窗口中的位置。 trafficLightPosition: { x: 12, y: 18 }, // 在windows上,设置默认显示窗口控制工具 titleBarOverlay: { color: "#fff", symbolColor: "black", } }) win.show()
在electron官网中有这么一段描述
titleBarStyle
String (可选) macOS Windows - 窗口标题栏样式。 默认值为 default
. 可能的值有
hidden
- 在一个隐藏的标题栏和一个全尺寸大小的内容窗口中取得结果。 在 macOS 内, 窗口将一直拥有位于左上的标准窗口控制器 (“traffic lights”)。- 在 Windows上,当与
titleBarOverlay: true
合并时,它将激活窗口控件叠加(详情请参阅titleBarOverlay
),否则将不会显示窗口控件
titleBarOverlay
Object | Boolean (可选) - 当使用无框窗口配置win.setWindowButtonVisibility(true)
在 macOS 或使用 titleBarStyle
可使标准窗口控制可见 ("traffic lights" on macOS) ,当前属性开启 Window Controls 覆盖 JavaScript APIs 和 CSS Environment Variables 指定 true
将导致覆盖默认系统颜色。 默认值为 false
.
这里说两者配合使用,即titleBarStyle
为hidden
,并且titleBarOverlay
为true
或者对象时,则windows系统中,应用窗口也会默认显示出window操作系统的窗口控件工具。
如图所示
这样我们就完成了,electron应用的无边框窗口。
但是这样的无边框窗口仅能实现通用的样式,应用头部总是会被占用一条高度。并且不支持自定义标题栏。若你有自定义标题栏,或者嵌入式的windows窗口控件需求,请继续往下看
2.创建windows窗口控件组件
因为我做的项目有windows窗口控件内嵌页面的需求,而且这样也方便自定义标题栏,所以需要有这样一个控件。例如下面这种情况
// 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="最小化图标" /> </li> <li @click="controlWindow(isFullScreen ? 3 : 2)"> <Icon :type="isFullScreen ? '最大化图标' : '恢复正常图标'" /> </li> <li class="close-icon" @click="controlWindow(0)"> <Icon type="关闭图标" /> </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 () { // 上来先设定当前窗口是否在最大化的状态 this.setIsFullScreen(remote.getCurrentWindow().isMaximized()) // 监听是否是最大化窗口 并 更改标识是否最大化 ipcRenderer.on('toggleMax', (e, isFullScreen) => { this.setIsFullScreen(isFullScreen) }) }, methods: { ...mapMutations(['setIsFullScreen']), controlWindow (val) { // 只有在2、3点击时,修改是否全屏状态 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) } } }
接下来 我们还需在主进程中,监听用户的放大、缩小、最小化、关闭的操作。
// background.js // win是窗口实例 win.on('maximize', (event) => { event.sender.send('toggleMax', true) }) win.on('unmaximize', (event) => { event.sender.send('toggleMax', false) })
准备工作做完了,接下来我们就可以来引用使用组件啦,如下
// home.vue <template> <div> <WindowsTopControl mainHeight="24" /> </div> </template> <script> import WindowsTopControl from './WindowsTopControl.vue' export default { components: { WindowsTopControl } } </script>
以上,我们就完成了自定义的windows控件组就完成了,记得将窗口设置中的titleBarOverlay注释掉!这样我们就能自定义标题栏和内嵌windows控件了。
三、后记
如果我们自定义控件这种方式实现的话,还需要考虑一点,那就是窗口的拖拽功能,一般情况下,我们拖拽的都是是窗口的头部。这里我们可以给窗口提前注入一个js,去创建一个拖拽条,内容如下
// WindowDrag.js // 在顶部插入一个的dom function initTopDrag () { const topDiv = document.createElement('div') // 创建节点 topDiv.style.position = 'fixed' // 一直在顶部 topDiv.style.top = '2px' topDiv.style.left = '2px' topDiv.style.height = '18px' // 顶部20px才可拖动 topDiv.style.width = 'calc(100% - 122px)' // 宽度100% topDiv.style.zIndex = '9999' // 悬浮于最外层 // topDiv.style.pointerEvents = 'none' // 用于点击穿透 // @ts-ignore topDiv.style['-webkit-user-select'] = 'none' // 禁止选择文字 // @ts-ignore topDiv.style['-webkit-app-region'] = 'drag' // 拖动 topDiv.id = 'drag-top-line' document.body.appendChild(topDiv) // 添加节点 } window.addEventListener('DOMContentLoaded', function onDOMContentLoaded () { initTopDrag() document.getElementById('drag-top-line').addEventListener('dblclick', e => { if (window.$isMac) { window.ipcRenderer.send('toggleMax') } }) })
在创建窗口时候引入
// background.js // 这里我将WindowDrag.js文件放在了public种 const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: `${__static}/WindowDrag.js`, } })
如此我们就完成了拖拽条的设置。(如图所示)
加载全部内容