Electron启程2-常用配置项(窗口配置)

渲染进程加载Electron

方式1

浏览器端无法加载electron,那么,我们可以使用preload预加载将需要的接口暴露出来。

创建一个preload.js文件,放在入口文件main.js的同级目录下。

1
2
3
global.electron = require('electron');
window.ipcRenderer = require('electron').ipcRenderer;
window.remote = require('electron').remote;

修改main.js文件
在入口文件中添加preload配置项,将preload.js作为预加载文件。预加载的时候还是可以使用nodejs里的api

1
2
3
4
5
6
7
8
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
preload: __dirname + '/preload.js'
}
});

在组件中如下使用即可。

1
2
3
4
5
6
7
const electron = window.electron;
const remote = window.remote;
console.log(electron)
console.log(remote.dialog)

const {dialog} = window.remote;
dialog.showErrorBox('title', 'content');

方式2

1
2
const { app, dialog } = window.require("electron").remote;
const electron = window.require('electron');

主进程和渲染进程数据共享

主进程

1
2
3
global.sharedObject = {
show_tongji: 0
}

设置值

1
global.sharedObject.show_tongji = 1;

取值

1
let show_tongji = global.sharedObject.show_tongji;

渲染进程

1
2
3
const remote = window.require('electron').remote;

remote.getGlobal('sharedObject').show_tongji = 1;

取值

1
let show_tongji = remote.getGlobal('sharedObject').show_tongji;

赋值

1
remote.getGlobal('sharedObject').show_tongji = 1;

基本配置

区分开发和生产环境

1
const isDevelopment = !app.isPackaged;

高DPI支持

1
2
3
4
if (process.platform === 'win32') {
app.commandLine.appendSwitch('high-dpi-support', 'true')
app.commandLine.appendSwitch('force-device-scale-factor', '1')
}

禁用硬件加速

非常重要 在一些集成显卡的电脑上,默认开启的硬件加速会导致应用看不到界面。

关闭硬件加速

1
app.disableHardwareAcceleration()

webview

HTML

1
2
3
4
<webview :src="url"
id="myweb"
class="myweb"
disablewebsecurity></webview>

JS

1
2
3
4
5
6
7
8
9
10
11
let isreload = false;
this.url = url;
this.$nextTick(() => {
const webview = document.querySelector('#myweb')
webview.addEventListener('dom-ready', () => {
if (!isreload) {
webview.reloadIgnoringCache()
isreload = true
}
})
})

CSS

1
2
3
4
5
.myweb {
width: 100%;
height: 100%;
display: flex;
}

初始化Win

1
2
3
4
5
6
7
8
9
10
11
new BrowserWindow({
width: 1130,
height: 650,
transparent: false,
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
webSecurity: false,
contextIsolation: false,
webviewTag: true
})

注意

窗口初始化要开启webviewTag

样式display: flex;保证内部充满

webview调用其方法要等页面dom-ready

窗口

窗口透明

1
2
3
4
5
6
7
const { BrowserWindow } = require('electron');
const win = new BrowserWindow({
transparent: true,
frame: false,
backgroundColor: '#00000000'
});
win.show();

注意

  • frame设置为false是为了用无边窗口

  • transparent设置为true是使用窗口的透明效果

  • backgroundColor为一个透明的颜色,是因为BrowserWindow默认的背景颜色是白色,设置透明之后,才能够真正地看到透明的效果。

    如果这个属性不设置会导致在有的电脑上是透明的有的不是,必须要设置。

系统配置

如果发现经过上述设置之后,窗口仍然不能透明的话,可能和Windows的设置有关
在Win7下,需要开启aero功能,在Win10下,需要开启颜色->透明效果

不显示菜单栏

1
2
3
4
5
const electron = require('electron')
/*获取electron窗体的菜单栏*/
const Menu = electron.Menu
/*隐藏electron创听的菜单栏*/
Menu.setApplicationMenu(null)

窗口状态

1
2
3
4
5
6
const { BrowserWindow } = require('electron');
const win = new BrowserWindow();
win.setProgressBar(0.5); // 任务栏中的进度条
let win = new BrowserWindow()
win.once('focus', () => win.flashFrame(false))
win.flashFrame(true) // 窗口闪烁

窗口显示和隐藏

窗口显示

1
2
3
4
5
6
7
8
9
10
11
12
13
if (win && !win.isDestroyed()) {
if (win.isMinimized()) {
win.restore()
}

if (!win.isVisible()) {
win.show()
}

win.focus();
} else {
// 创建窗口
}

窗口隐藏

1
2
3
if (win && !win.isDestroyed()) {
win.hide();
}

窗口托栏图标闪烁

1
win.flashFrame(true);

窗口位置

1
2
3
4
5
6
7
8
const win = window.require("electron").remote.getCurrentWindow();
const {screen} = window.require("electron").remote;

let display = screen.getPrimaryDisplay();
let x = display.bounds.width - 80;
let y = display.bounds.height - 630 - 44;
win.setSize(76, 630)
win.setPosition(x, y)

窗口居中

1
win.center();

窗口大小

1
2
win.setContentSize(160, 120);
win.setSize(160, 120);

注意

如果设置窗口变小 直接调用setSize是不生效的,要调用setContentSize修改内部尺寸才能改变窗口大小。

获取窗口句柄

1
2
3
4
const win = window.require("electron").remote.getCurrentWindow();
let hwnd = win.getNativeWindowHandle();
let winId = hwnd.readUInt32LE(0);
console.info("winId", winId);

禁用右键菜单

1
2
3
4
5
6
7
8
9
10
function preventDragbarContext(win) {
var WM_INITMENU = 0x116;//278
win.hookWindowMessage(WM_INITMENU, function (e) {
win.setEnabled(false);
setTimeout(() => {
win.setEnabled(true);
}, 100);
return true;
})
}

标题栏或者设置css的 -webkit-app-region: drag;的元素,当接收到右键的时候进行拦截,先设置窗口禁用,然后定时恢复。

特殊处理

1
2
app.disableDomainBlockingFor3DAPIs();   // 关闭3D api, 提高兼容性
app.disableHardwareAcceleration(); // 关闭硬件加速, 减少渲染问题

最大化最小化/显示隐藏/获得焦点

API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 渲染进程获取窗口
const win = window.require("electron").remote.getCurrentWindow();

// 返回 Boolean - 判断窗口是否最大化
win.isMaximized()
// 最大化
win.maximize()
// 取消窗口最大化
win.unmaximize()

// 返回 Boolean -判断窗口是否最小化
win.isMinimized()
// 最小化
win.minimize()
// 将窗口从最小化状态恢复到以前的状态。
win.restore()

// 返回 Boolean - 判断窗口是否聚焦
win.isFocused()
// 聚焦于窗口
win.focus()
// 取消窗口的聚焦
win.blur()

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if (win && !win.isDestroyed()) {
if (win.isMinimized()) {
win.restore()
}

if (!win.isVisible()) {
win.show()
}

if (!win.isFocused()) {
win.focus()
}
} else {
createFun()
}

双击最大化问题

Electron无边框模式下-webkit-app-region: drag;双击最大化的问题
废话不多说 使用以下api即可解决:

1
2
3
4
5
mainWindow.setMenu(null);
// 设置窗口是否可以由用户手动最大化
mainWindow.setMaximizable(false);
// 设置用户是否可以调节窗口尺寸
mainWindow.setResizable(false);

或者创建窗口设置属性

1
2
maximizable: false,
minimizable: false,

防止窗口加载闪烁

1
2
3
4
5
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ show: false })
win.once('ready-to-show', () => {
win.show()
})

防止透明窗口显示闪烁

main.js中添加

1
app.commandLine.appendSwitch('wm-window-animations-disabled');

创建无边框窗口

1
2
3
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 600, frame: false })
win.show()

禁止缩放

1
2
3
new BrowserWindow({  
resizable: false
})

事件穿透

点击穿透窗口

1
2
3
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
win.setIgnoreMouseEvents(true)

转发

忽略鼠标消息会使网页无视鼠标移动,这意味着鼠标移动事件不会被发出。 在 Windows 操作系统上,可以使用可选参数将鼠标移动消息转发到网页,从而允许发出诸如 mouseleave 之类的事件:

1
2
3
4
5
6
7
8
const win = require('electron').remote.getCurrentWindow()
const el = document.getElementById('clickThroughElement')
el.addEventListener('mouseenter', () => {
win.setIgnoreMouseEvents(true, { forward: true })
})
el.addEventListener('mouseleave', () => {
win.setIgnoreMouseEvents(false)
})

这将使网页在 el 上点击时穿透,在它外面时恢复正常。

渲染进程关闭窗口

1
2
3
const remote = require('electron').remote;
const win = remote.getCurrentWindow();
win.close();

应用关闭

1
2
const {app} = require('electron').remote;
app.close();

窗口 不在任务栏显示

1
homeWin.setSkipTaskbar(true)

true 表示不显示,false 表示显示。

获取焦点闪烁

1
2
win.once('focus', () => win.flashFrame(false))
win.flashFrame(true)

注意

别忘了调用 win.flashFramework(false) 来关闭闪烁。 在上面的示例中, 当窗口进入焦点时会调用它, 但您可能会使用超时或其他一些事件来禁用它。

点击任务栏不隐藏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let homeWin = new BrowserWindow({
width: 1280,
height: 768,
fullscreen: true,
simpleFullscreen: true,
minimizable: false,
frame: false,
resizable: false,
transparent: true,
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
webSecurity: false,
contextIsolation: false,
},
});
homeWin.setFullScreen(true);
homeWin.setAlwaysOnTop(true, "pop-up-menu");

只设置simpleFullscreen: true,homeWin.setAlwaysOnTop(true, "pop-up-menu");的话,虽然窗口全屏了,但是一点击任务栏上的图标,界面就隐藏了,所以一定要添加上

1
homeWin.setFullScreen(true);

可能你会说直接隐藏任务栏图标不就行了

1
homeWin.setSkipTaskbar(true)

但是这样配置会导致任务栏会遮挡窗口,就算设置窗口置顶也没用,暂时没找到解决方法。

可拖拽和不可拖拽

1
2
3
4
5
6
7
body{
-webkit-app-region: drag;
}

button {
-webkit-app-region: no-drag;
}

常用方式

如果窗口设置的可拖拽,那么按钮或需要触发点击的就取消拖拽,否则事件无法触发。

禁用文本选择

1
2
3
4
.titlebar {
-webkit-user-select: none;
-webkit-app-region: drag;
}

自定义滚动条

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
::-webkit-scrollbar { /*滚动条整体样式*/
width: 10px; /*高宽分别对应横竖滚动条的尺寸*/
height: 1px;
}

::-webkit-scrollbar-thumb { /*滚动条里面小方块*/
border-radius: 10px;
-webkit-box-shadow: inset 0 0 5px #960200;
background: #960200;
}

::-webkit-scrollbar-track { /*滚动条里面轨道*/
-webkit-box-shadow: inset 0 0 5px #EDEDED;
border-radius: 10px;
background: #EDEDED;
}

取消input选中样式

1
outline: none;

设置checkbox选中背景色

1
<input type="checkbox" id="remeberpwd"/> <label for="remeberpwd">记住密码</label>

样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
input[type=checkbox]{
cursor: pointer;
position: relative;
width: 15px;
height: 15px;
font-size: 14px;
border-radius: 4px;
}

input[type=checkbox]::after{
position: absolute;
top: 0;
color: #ffffff;
width: 15px;
height: 15px;
display: inline-block;
visibility: visible;
padding-left: 0;
text-align: center;
content: ' ';
border-radius: 3px
}

input[type=checkbox]:checked::after{
content: "✓";
font-size: 12px;
background-color: #33C5B3;
border-radius: 2px;
}

禁止图片拖动

1
2
3
img {
-webkit-user-drag: none;
}

禁用Console警告信息

cross-env是一款跨平台设置和使用环境变量的脚本

1
npm install --save-dev cross-env

禁用

1
cross-env ELECTRON_DISABLE_SECURITY_WARNINGS=true

比如原来我的启动命令为

1
2
3
"scripts": {
"start": "webpack --mode development && electron .",
}

就改为

1
2
3
"scripts": {
"start": "webpack --mode development && cross-env ELECTRON_DISABLE_SECURITY_WARNINGS=true electron .",
}

隐藏掉这些警告信息,仅仅是个掩耳盗铃的行为,并不值得推荐使用。一定要看看警告是否能解决,不能解决又有强迫症的可以这样做。

Dev-Tools

安装本地Dev-Tools插件

官方文档:https://www.electronjs.org/docs/api/browser-window#browserwindowadddevtoolsextensionpath-deprecated

插件下载地址

链接:https://pan.baidu.com/s/19BzaBnZsWZxN_thHHvSYBw
提取码:psvm

Electron不同版本的API不一样

早期版本

1
2
3
4
5
6
7
const isDevelopment = !app.isPackaged;
app.whenReady().then(() => {
if (isDevelopment && !process.env.IS_TEST) {
BrowserWindow.addDevToolsExtension(path.resolve(__dirname, "./vue-devtools"))
}
createWindow();
});

新版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const isDevelopment = !app.isPackaged;
app.whenReady().then(() => {
if (isDevelopment && !process.env.IS_TEST) {
try {
// 安装vue-devtools
const {session} = require("electron");
const path = require("path");
session.defaultSession.loadExtension(
path.resolve(__dirname, "./vue-devtools") //这个是插件目录
);
} catch (e) {
console.error("Vue Devtools failed to install:", e.toString());
}
}
createWindow();
});

打开devtools

1
mainWindow.webContents.openDevTools();

默认状态下,开发者工具的位置是上一次工具打开的位置(左边,右边,下边都有可能。取决于上一次的状态,但不会是分离状态,也没有处于顶部的状态)。

界面右侧打开

1
mainWindow.webContents.openDevTools({mode:'right'});

界面底部打开

1
mainWindow.webContents.openDevTools({mode:'bottom'});

界面左侧打开

1
mainWindow.webContents.openDevTools({mode:'left'});

分离状态打开

1
mainWindow.webContents.openDevTools({mode:'detach'});

DIV可拖动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
drag_user_camera() {
let that = this;
let user_camera = this.$refs["user_camera"];

let camera_outer = this.$refs["camera_outer"];
camera_outer.addEventListener('mousedown', mouseDown, false);

document.addEventListener('mouseup', mouseUp, false);

function mouseDown() {
document.addEventListener('mousemove', sliderMove, false);
}

function mouseUp() {
document.removeEventListener('mousemove', sliderMove, false);
if (that.camera_big) {
return
}
let myleft = parseInt(user_camera.style.left);
let mytop = parseInt(user_camera.style.top);
if (mytop < 0) {
mytop = 0;
}
if (mytop + user_camera.clientHeight > document.body.clientHeight) {
mytop = document.body.clientHeight - user_camera.clientHeight;
}

if (myleft < user_camera.clientWidth / 2) {
myleft = user_camera.clientWidth / 2;
}

if (myleft + user_camera.clientWidth / 2 > document.body.clientWidth) {
myleft = document.body.clientWidth - user_camera.clientWidth / 2;
}
user_camera.style.left = myleft + 'px';
user_camera.style.top = mytop + 'px';
}

function sliderMove(e) {
if (that.camera_big) {
return
}
user_camera.style.left = e.clientX + 'px';
user_camera.style.top = e.clientY - (user_camera.clientHeight / 2) + 'px';
}
},

图片置灰

1
2
3
4
5
6
7
8
.userhead.gray {
-webkit-filter: grayscale(100%);
-moz-filter: grayscale(100%);
-ms-filter: grayscale(100%);
-o-filter: grayscale(100%);
filter: grayscale(100%);
filter: gray;
}

预处理脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 添加preload.js
const path = require('path');
mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
});
// preload.js的实现
const {ipcRenderer, remote, clipboard} = require('electron');
window.addEventListener('DOMContentLoaded', () => {
const element = document.getElementById('chrome-version');
if (element) {
element.innerText = process.versions['chrome'];
}
});