文章目录
一、目标原型1. 目标2. 原型设计3. 原型初步实现二、无边框窗口1. 要点2. 改造三、可拖拽区1. 要点2. 改造四、最小化、最大化、关闭1. 要点2. 改造五、动态改变窗口大小1. 要点2. 改造六、扩展扩展1:在内嵌的独立项目中怎么实现拖拽、最大化、最小化、关闭?扩展2:在``标签内嵌的页面中怎么实现拖拽、最大化、最小化、关闭?扩展3:如何在Electron关闭时执行cmd命令扩展4:系统托盘tray七、源码下载一、目标原型
1. 目标
实现一个无边框窗口,包括最小化、最大化、关闭、拖动等功能动态改变窗口大小,即在页面跳转的时候根据需要改变窗口大小2. 原型设计
(1) 登录窗口(500×300)
点击登录跳转到首页
(2) 首页(全屏)
跳转到首页,自动全屏包括最小化、最大化、关闭,以及灰色区域可拖动整个窗口功能
3. 原型初步实现
创建login.html和index.html页面,实现原型页面基本效果,下文逐步改造,实现Electron无边框窗口。
二、无边框窗口
1. 要点
要创建无边框窗口,只需在BrowserWindow的options中将frame设置为 false:
const {BrowserWindow } = require('electron')let win = new BrowserWindow({width: 800, height: 600, frame: false })win.show()
通过将 transparent 选项设置为 true, 还可以使无框窗口透明:
let win = new BrowserWindow({ transparent: true, frame: false })
参考地址:/docs/api/frameless-window#%E9%80%8F%E6%98%8E%E7%AA%97%E5%8F%A3
2. 改造
在main.js
文件中添加frame:false
:
mainWindow = new BrowserWindow({width: 800,height: 600,frame:false,webPreferences: {/*preload: path.join(__dirname, 'preload.js')*/nodeIntegration: true}})
注意:webPreferences的值,如果写preload无nodeIntegration,会影响后面最大最小化功能不起作用,暂不明白原因。
三、可拖拽区
1. 要点
应用程序需要在 CSS 中指定-webkit-app-region: drag
来告诉 Electron 哪些区域是可拖拽的在可拖拽区域内部使用-webkit-app-region: no-drag
则可以将其中部分区域排除拖动行为可能与选择文本冲突。 例如, 当您拖动标题栏时, 您可能会意外地选择标题栏上的文本。 为防止此操作, 您需要在可区域中禁用文本选择.titlebar {-webkit-app-region: drag;-webkit-user-select: none;}
在某些平台上,可拖拽区域不被视为窗口的实际内容,而是作为窗口边框处理,因此在右键单击时会弹出系统菜单。 要使上下文菜单在所有平台上都正确运行, 您永远也不要在可拖拽区域上使用自定义上下文菜单。备注:如果你在某些页面设置了可拖拽区,跳转到一个新的页面,而这个新的页面没有设置可拖拽区,则会沿用上一页面的可拖拽区,感觉很奇怪,也没有相应的dom支持,就像取用的上一页面固定的像素区域一样(测试发现是这样,不准确之处请指正,谢谢)。如果拖拽区域不同,这种情况下,在新的页面中设置上拖拽区域即可。
2. 改造
修改index.html
页面中的样式,添加相应drag和no-drag特性
<div class="topbar" style="-webkit-app-region: drag;-webkit-user-select: none;"><div class="logo fl"><img src="images/logo.png" alt=""><span>这里写软件名称</span></div><ul class="menu fl" style="-webkit-app-region: no-drag;"><li>菜单1</li><li>菜单2</li><li>菜单3</li><li>菜单4</li></ul><div class="min_max_close fr" style="-webkit-app-region: no-drag;"><img src="images/min.png" id="min" alt=""><img src="images/max.png" id="max" alt=""><img src="images/close.png" id="close" alt=""></div></div>
四、最小化、最大化、关闭
1. 要点
render 进程通过 ipcRenderer 与 ipcMain 进行通讯,以通知 main 进程操作窗体。2. 改造
(1) 在renderer.js中添加click事件,发送操作命令给主进程
let ipcRenderer = require('electron').ipcRenderer;var max = document.getElementById('max');if (max) {max.addEventListener('click', () => {//发送最大化命令ipcRenderer.send('window-max');//最大化图形切换if (max.getAttribute('src') == 'images/max.png') {max.setAttribute('src', 'images/maxed.png');} else {max.setAttribute('src', 'images/max.png');}})}var min = document.getElementById('min');if (min) {min.addEventListener('click', () => {//发送最小化命令ipcRenderer.send('window-min');})}var close = document.getElementById('close');if (close) {close.addEventListener('click', () => {//发送关闭命令ipcRenderer.send('window-close');})}
(2) 在main.js中接收操作命令,做出相应处理
let ipcMain = require('electron').ipcMain;//接收最小化命令ipcMain.on('window-min', function() {mainWindow.minimize();})//接收最大化命令ipcMain.on('window-max', function() {if (mainWindow.isMaximized()) {mainWindow.restore();} else {mainWindow.maximize();}})//接收关闭命令ipcMain.on('window-close', function() {mainWindow.close();})
补充:这里最大化和取消最大化时,修改图标的方法不合适,因为通过双击drag-area或者拉动窗口到屏幕边缘等操作,也可能修改窗口的状态。
因此,应该在主进程中监听窗口的最大化操作,然后发送命令给渲染进程:
mainWindow.on('maximize', function () {mainWindow.webContents.send('main-window-max');})mainWindow.on('unmaximize', function () {mainWindow.webContents.send('main-window-unmax');})
在渲染进程中接收到相应命令,再进行处理:
ipcRenderer.on('main-window-max', (event) => {max.classList.remove('icon-max');max.classList.add('icon-maxed');});ipcRenderer.on('main-window-unmax', (event) => {max.classList.remove('icon-maxed');max.classList.add('icon-max');});
五、动态改变窗口大小
1. 要点
思路同最小化、最大化、关闭,仅添加了页面调转。
2. 改造
(1) 在main.js中设置启动初始页面为login.html
mainWindow.loadFile('login.html')
(2) 在renderer.js中添加login按钮的click事件,发送最大化给主进程
var loginbtn = document.getElementById('login');if (loginbtn) {loginbtn.addEventListener('click', () => {ipcRenderer.send('window-max');location.href = "index.html";})}
六、扩展
扩展1:在内嵌的独立项目中怎么实现拖拽、最大化、最小化、关闭?
如果你只是用Electron打个包,用它的浏览器功能,里面还是一个完整的其它项目,比如一个普通的java web项目,相当于只是穿层衣服。怎么在里边实现以上最小化、最大化、关闭、拖动等功能呢?
首先创建一个完全独立的nodejs项目,创建一个index页面,其中有最小化、最大化、关闭按钮和拖拽区
在Electron项目index.html中直接跳转到独立项目页面
<script type="text/javascript">window.location='http://localhost:8888/index.html';</script>
实现可拖拽区
同上加上样式即可:style="-webkit-app-region: drag;-webkit-user-select: none;"
实现最小化、最大化、关闭
关键的有两步:
(1)在main.js
中new BrowserWindow加上nodeIntegration: true
mainWindow = new BrowserWindow({width: 500,height: 300,frame: false,webPreferences: {nodeIntegration: true}})
(2)在独立项目中加上之前的renderer.js文件,在页面中引入renderer.js
<script type="text/javascript" src="renderer.js"></script>
其实不应该这样做,应该可以直接写require('./renderer.js')
的,但是这样要求在electron项目中把renderer.js export出来,由于我语法不熟,就直接拷过去了,先不研究了。
扩展2:在<webview>
标签内嵌的页面中怎么实现拖拽、最大化、最小化、关闭?
在webview标签上加上nodeintegration
属性:
<webview src="/" nodeintegration></webview>
当有此属性时, webview 中的访客页(guest page)将具有Node集成, 并且可以使用像 require 和 process 这样的node APIs 去访问低层系统资源。
扩展3:如何在Electron关闭时执行cmd命令
两种实现方式:/article/170628.htm
我的需求比较简单,简单实现如下:
//接收关闭命令ipcMain.on('window-close', function() {let closeProcess = child_process.exec('taskkill /f /im XXXXX.exe');closeProcess.on('close', function (code) {mainWindow.close();})})
扩展4:系统托盘tray
在任务栏右下角添加图标和右键菜单。查看Electron tray文档即可。
七、源码下载
Electron无边框窗口(最小化、最大化、关闭、拖动)以及动态改变窗口大小
在Electron内嵌的独立项目中怎么实现拖拽、最大化、最小化、关闭
references
[1] 无边框窗口 | Electron
[2] Electron 无边框窗口最大化最小化关闭功能
[3] electron 改变窗体大小
[4] BrowserWindow配置说明文档
[5] webview标签说明文档