文章目录
- 相关笔记
- 笔记说明
- 一、轻松入门
- 1、搭建开发环境
- 2、创建窗口界面
- 3、调试主进程
- 二、主进程和渲染进程
- 1、进程互访
- 2、渲染进程访问主进程类型
- 3、渲染进程访问主进程自定义内容
- 4、渲染进程向主进程发送消息
- 5、主进程向渲染进程发送消息
- 6、多个窗口的渲染进程接收主进程发送的消息
- 7、渲染进程之间消息传递
- 方法一:利用主进程进行中转
- 方法二:单向传递
相关笔记
- Electron学习笔记(一)
- Electron学习笔记(二)
- 使用 electron-vite-vue 构建 electron + vue3 项目并打包
笔记说明
文本为学习《Electron 实战 入门、进阶与性能优化 刘晓伦 著》时所记录的笔记 主要将书本上的案例运行一遍,针对原理部分并无相关记录。笔记记录于 2023年9月。
一、轻松入门
1、搭建开发环境
安装 yarn :
npm i -g yarn
创建一个文件夹,进行项目的初始化:
yarn init -y
配置 Electron 的镜像网站:
yarn config set electron_mirror https://registry.npmmirror.com/-/binary/electron/
使用 yarn 安装 Electron:
yarn add electron --dev
2、创建窗口界面
创建一个 index.html 文件,内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Electron</title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
新建一个 index.js 文件,内容如下:
const {app,BrowserWindow} = require('electron');
let win = null;
app.on('ready', function() {
win = new BrowserWindow({
// 为页面集成Node.js环境
webPreferences: {
nodeIntegration: true
}
});
// 访问资源文件
win.loadFile('index.html');
// 程序启动后开启 开发者工具
// win.webContents.openDevTools();
win.on('close',function() {
win = null;
})
});
app.on('window-all-closed',function() {
app.quit();
})
更新 package.json 文件:
"scripts": {
"start": "electron ./index.js"
},
启动项目:
yarn start
结果展示:
3、调试主进程
点击调试按钮,创建 launch.json 文件 -> 选择Node.js环境
修改 launch.json 文件如下:
{
"version": "0.2.0",
"configurations": [
{
"name": "调试主进程",
// type: 调试环境为 Node.js 环境
"type": "node",
"request": "launch",
"cwd": "${workspaceRoot}",
// runtimeExecutable: 指向的是批处理文件,该批处理文件用于启动 Electron
// ${workspaceRoot} 是正在进行调试的程序的工作目录的绝对路径
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron.cmd"
},
// 此处的参数是主进程程序路径的简写形式,填写 "./index.js" 亦可
"args": ["."],
"outputCapture": "std"
}
]
}
快捷键:
Ctrl
+Shift
+I
:打开渲染进程的调试窗口
Ctrl
+R
:代码修改后,刷新界面
二、主进程和渲染进程
1、进程互访
注:原书籍中的代码由于 Electron 版本的更新,remote 模块无法直接导入使用,需要进行下载:
下载 remote 模块:
yarn add @electron/remote
更新 index.js 文件如下:(主进程代码)
const {app,BrowserWindow} = require('electron');
app.on('ready', function() {
win = new BrowserWindow({
// 为页面集成Node.js环境
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
require("@electron/remote/main").initialize();
require("@electron/remote/main").enable(win.webContents);
// 访问资源文件
win.loadFile('index.html');
// 程序启动后开启 开发者工具
// win.webContents.openDevTools();
win.on('close',function() {
win = null;
})
});
app.on('window-all-closed',function() {
app.quit();
})
参考链接:https://blog.csdn.net/m0_45961428/article/details/122982510
在 index.html 添加以下代码:
<button id="openDevToolsBtn">打开开发者工具</button>
<script>
const remote =require('@electron/remote');
document.querySelector('#openDevToolsBtn').addEventListener('click',function() {
remote.getCurrentWindow().webContents.openDevTools();
})
</script>
运行程序:
yarn start
运行结果:(点击按钮可打开开发者工具)
2、渲染进程访问主进程类型
主进程代码:主进程代码
更新 index.html 文件如下:
<button id="makeNewWindow">创建新窗口</button>
<script>
const remote = require('@electron/remote');
// 在渲染进程中创建一个新的窗口
document.querySelector('#makeNewWindow').addEventListener('click',function() {
win = new remote.BrowserWindow({
webPreferences: {
nodeIntegration: true,
}
});
win.loadFile('newWin.html');
});
</script>
说明:创建 BrowserWindow 的过程依然在主进程中进行,是由 remote 模块通知主进程完成相应的操作的,主进程创建了 BrowserWindow 对象的实例后,把对象的实例以远程对象的形式返回给渲染进程。
3、渲染进程访问主进程自定义内容
主进程代码:主进程代码
新建文件 mainModel.js:
let {BrowserWindow} = require('electron');
exports.makeWin = function() {
let win = new BrowserWindow({
webPreferences: {
nodeIntegration: true,
}
});
return win;
}
更新 index.html 文件如下:
<button id="makeNewWindow2">创建新窗口2</button>
<script>
const remote = require('@electron/remote');
const mainModel = remote.require('./mainModel');
let win2 = null;
document.querySelector('#makeNewWindow2').addEventListener('click',function() {
win2 = mainModel.makeWin();
win2.loadFile('newWin.html');
});
</script>
4、渲染进程向主进程发送消息
更新 index.html 文件:
<button id="sendMsg">向主进程发送消息</button>
<script>
const {ipcRenderer} = require('electron');
document.querySelector('#makeNewWindow2').addEventListener('click',() => {
// msg:消息管道的名称
ipcRenderer.send('msg',{name: 'xiaom'},{name: 'xiaoh'});
});
</script>
index.js 文件添加以下内容:(其余主进程代码见:主进程代码)
const {ipcMain} = require('electron');
ipcMain.on('msg',(event,param1,param2) => {
console.log(param1);
console.log(param2);
console.log(event.sender);
})
运行结果:
5、主进程向渲染进程发送消息
在主进程 index.js 文件中添加以下代码:
const {app,BrowserWindow} = require('electron');
const {ipcMain} = require('electron');
let win = null;
app.on('ready', function() {
win = new BrowserWindow({
// 为页面集成Node.js环境
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
// 监听渲染进程发来的消息,随后再次发回给渲染进程
ipcMain.on('msg',(event,param1,param2) => {
win.webContents.send('msg_main',param1,param2);
})
// 访问资源文件
win.loadFile('index.html');
win.on('close',function() {
win = null;
})
});
更新渲染进程 index.html 文件如下:
<button id="sendMsg">向主进程发送消息</button>
<script>
const {ipcRenderer} = require('electron');
// 接收 主进程发送的消息
ipcRenderer.on('msg_main',(event,param1,param2) => {
console.log(param1);
console.log(param2);
console.log(event.sender);
})
document.querySelector('#sendMsg').addEventListener('click',() => {
ipcRenderer.send('msg',{name: 'xiaom'},{name: 'xiaoh'});
});
</script>
运行程序后 -> 点击按钮(向主进程发送消息) -> Electron 程序控制台将会打印主进程发送来的消息。
运行结果:
6、多个窗口的渲染进程接收主进程发送的消息
更新主进程 index.js 文件:
const {app,BrowserWindow} = require('electron');
const {ipcMain} = require('electron');
// 接收 渲染进程 发送来的消息 在VSCode控制台打印消息
ipcMain.on('msg',(event,param1,param2) => {
console.log(param1);
console.log(param2);
console.log(event.sender);
});
let win = null;
app.on('ready', function() {
win = new BrowserWindow({
// 为页面集成Node.js环境
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
// 为了使 remote 模块能够使用需要执行以下操作
require("@electron/remote/main").initialize();
require("@electron/remote/main").enable(win.webContents);
// 监听 渲染进程 发来的消息,随后再次发回给渲染进程
ipcMain.on('msg',(event,param1,param2) => {
// 单个窗口时使用:
// win.webContents.send('msg_main',param1,param2);
// 多个窗口时使用
// 方法一:
// event.sender.send('msg_main',param1,param2);
// 方法二:
event.reply('msg_main',param1,param2);
})
// 访问资源文件
win.loadFile('index.html');
win.on('close',function() {
win = null;
})
});
app.on('window-all-closed',function() {
app.quit();
});
更新 index.html 文件如下:
<button id="makeNewWindow">创建新窗口</button>
<button id="sendMsg">向主进程发送消息</button>
<script>
const remote = require('@electron/remote');
const { ipcRenderer } = require('electron');
// 在渲染进程中创建一个新的窗口
document.querySelector('#makeNewWindow').addEventListener('click', function () {
win = new remote.BrowserWindow({
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
win.loadFile('newWin.html');
});
// 监听主进程发送来的消息
ipcRenderer.on('msg_main', (event, param1, param2) => {
console.log(param1);
console.log(param2);
console.log(event.sender);
})
// 点击发送按钮 发送消息至主进程
document.querySelector('#sendMsg').addEventListener('click', () => {
ipcRenderer.send('msg', { name: 'xiaom' }, { name: 'xiaoh' });
});
</script>
newWin.html 文件内容如下:
<h1>newWindow</h1>
<button id="sendMsg2">向主进程发送消息</button>
<script>
const { ipcRenderer } = require('electron');
// 监听主进程发送来的消息
ipcRenderer.on('msg_main', (event, param1, param2) => {
console.log(param1);
console.log(param2);
console.log(event.sender);
})
// 点击发送按钮 发送消息至主进程
document.querySelector('#sendMsg2').addEventListener('click', () => {
ipcRenderer.send('msg', { name: 'xiaod' }, { name: 'xiaoc' });
});
</script>
7、渲染进程之间消息传递
一个程序有多个窗口,并要在窗口之间传递消息,可以通过主进程中转,此处通过win1先将消息发送给主进程,主进程再将消息发送给win2。
方法一:利用主进程进行中转
窗口(win1) --> 主进程(中转) --> 窗口(win2)
窗口(win2) --> 主进程(中转) --> 窗口(win1)
主进程 index.js 文件内容如下:
const {app,BrowserWindow} = require('electron');
const {ipcMain} = require('electron');
let win = null;
app.on('ready', function() {
win = new BrowserWindow({
// 为页面集成Node.js环境
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
require("@electron/remote/main").initialize();
require("@electron/remote/main").enable(win.webContents);
// 监听 窗口win1 (index.html) 发来的消息
ipcMain.on('msg_1',(event,param1,param2) => {
// 向 窗口win1 (index.html) 发送消息
win.webContents.send('msg_main',param1,param2);
});
// 访问资源文件
win.loadFile('index.html');
// 程序启动后开启 开发者工具
win.webContents.openDevTools();
win.on('close',function() {
win = null;
})
});
app.on('window-all-closed',function() {
app.quit();
})
窗口(win1) index.html 文件内容如下:
<h1>win1</h1>
<button id="makeNewWindow">创建新窗口win2</button>
<button id="sendMsg">向主进程发送消息</button>
<script>
const remote = require('@electron/remote');
const { ipcRenderer } = require('electron');
// 在渲染进程中创建一个新的窗口(win2)
document.querySelector('#makeNewWindow').addEventListener('click', function () {
win2 = new remote.BrowserWindow({
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
win2.loadFile('win2.html');
win2.webContents.openDevTools();
// 接收 主进程 的消息后 向 win2 发送消息
ipcRenderer.on('msg_main', (event, param1, param2) => {
win2.webContents.send('msg_win2',param1,param2);
});
});
// 接收 主进程 发送的消息
ipcRenderer.on('msg_main', (event, param1, param2) => {
console.log(param1);
console.log(param2);
console.log(event.sender);
})
// 点击按钮向 主进程 发送消息
document.querySelector('#sendMsg').addEventListener('click', () => {
ipcRenderer.send('msg_1', { name: 'xiaom' }, { name: 'xiaoh' });
});
</script>
窗口(win2) win2.html 文件内容如下:
<h1>win2</h1>
<button id="sendMsg2">向主进程发送消息</button>
<script>
const { ipcRenderer } = require('electron');
// 接收 窗口 win1 (index.html) 发送来的消息
ipcRenderer.on('msg_win2', (event, param1, param2) => {
console.log(param1);
console.log(param2);
console.log(event.sender);
})
// 点击按钮向 主进程 发送消息
document.querySelector('#sendMsg2').addEventListener('click', () => {
ipcRenderer.send('msg_1', { name: 'xiaod' }, { name: 'xiaoc' });
});
</script>
结果展示:
方法二:单向传递
窗口(win1) --> 窗口(win2)
主进程 index.js 文件内容如下:(此方法无需主进程中转,所以主进程无需接收消息)
const {app,BrowserWindow} = require('electron');
let win = null;
app.on('ready', function() {
win = new BrowserWindow({
// 为页面集成Node.js环境
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
require("@electron/remote/main").initialize();
require("@electron/remote/main").enable(win.webContents);
// 访问资源文件
win.loadFile('index.html');
// 程序启动后开启 开发者工具
win.webContents.openDevTools();
win.on('close',function() {
win = null;
})
});
app.on('window-all-closed',function() {
app.quit();
});
窗口(win1) index.html 文件内容如下:
<h1>win1</h1>
<button id="makeNewWindow">创建新窗口win2</button>
<button id="sendMsg">向窗口win2发送消息</button>
<script>
const remote = require('@electron/remote');
const { ipcRenderer } = require('electron');
// 在渲染进程中创建一个新的窗口(win2)
document.querySelector('#makeNewWindow').addEventListener('click', function () {
win2 = new remote.BrowserWindow({
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
});
win2.loadFile('win2.html');
win2.webContents.openDevTools();
// 获取 窗口(win2) 的 webContents.id 并通过 ipcRenderer.sendTo 方法发送消息至 win2
document.querySelector('#sendMsg').addEventListener('click', () => {
ipcRenderer.sendTo(win2.webContents.id,'msg_win2', { name: 'xiaom' }, { name: 'xiaoh' });
});
});
</script>
窗口(win2) win2.html 文件内容如下:
<h1>win2</h1>
<script>
const { ipcRenderer } = require('electron');
// 接收 窗口(win1) 发送来的消息
ipcRenderer.on('msg_win2', (event, param1, param2) => {
console.log(param1);
console.log(param2);
console.log(event.sender);
});
</script>
结果展示: