文章目錄
- 相關筆記
- 筆記說明
- 一、輕松入門
- 1、搭建開發環境
- 2、創建窗口界面
- 3、調試主進程
- 二、主進程和渲染進程
- 1、進程互訪
- 2、渲染進程訪問主進程類型
- 3、渲染進程訪問主進程自定義內容
- 4、渲染進程向主進程發送消息
- 5、主進程向渲染進程發送消息
- 6、多個窗口的渲染進程接收主進程發送的消息
- 7、渲染進程之間消息傳遞
- 方法一:利用主進程進行中轉
- 方法二:單向傳遞
相關筆記
- Electron學習筆記(一)
- Electron學習筆記(二)
- Electron學習筆記(三)
- Electron學習筆記(四)
- 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 方法發送消息至 win2document.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>
結果展示: