Electron进程间通信
使用electron编写程序时经常遇到下面这种场景:
当用户点击一个按钮时,需要将页面输入的信息保存到本地电脑上;
或者是点击菜单时,需要页面窗口做出响应。
用户点击的按钮和窗口展示的内容是运行在渲染进程中,而保存的操作和点击菜单是运行在主进程中的,渲染进程和主进程无法直接通信,
这是就需要使用到进程间通信(IPC)
为了实现这种通信,Electron提供了 ipcMain
和 ipcRenderer
模块。
渲染进程到主进程的通信
下面是一个简单的例子,介绍在页面输入文本信息,然后点击按钮将文本信息保存到本地电脑,然后点击查询,读取本地电脑文件并将读取的文本展示出来。
main.js
const { app, BrowserWindow, ipcMain } = require('electron')
const {join} = require("path");
const fs = require("fs");
// 应用创建窗口
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: join(__dirname, 'preload.js')
}
})
win.loadFile('index.html')
win.webContents.openDevTools();
}
app.whenReady().then(() => {
// 处理保存文本的事件
ipcMain.handle('save-text', async (event, text) => {
const filePath = `./output.txt`;
fs.writeFileSync(filePath, text);
});
// 处理查询文本的事件
ipcMain.handle('query-text', async (event) => {
const filePath = `./output.txt`;
return fs.readFileSync(filePath, {encoding: 'utf-8'});
});
createWindow()
})
preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
saveText: (text) => ipcRenderer.invoke('save-text', text),
queryText: () => ipcRenderer.invoke('query-text'),
})
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<label>
输入文本信息:
<input id="input-name" type="text">
</label>
<input id="save" type="button" value="保存">
<div>
<input id="query" type="button" value="读取文本信息">
<div id="text"></div>
</div>
<script>
const saveButton = document.getElementById('save')
saveButton.addEventListener('click', () => {
const inputName = document.getElementById('input-name')
window.myAPI.saveText(inputName.value)
})
const queryButton = document.getElementById('query')
queryButton.addEventListener('click', async () => {
const text = document.getElementById('text')
text.innerHTML = await window.myAPI.queryText()
})
</script>
</body>
</html>
运行结果如下:
输入hello world!
,点击保存,然后点击读取按钮,就会把保存的文件内容展示出来。
这个是渲染进程到主进程的通信,下面介绍一下主进程到渲染进程的通信。
主进程到渲染进程的通信
我们在窗口添加一个设置菜单和两个子菜单+1,-1,
点击子菜单时页面数字做出相应反馈。
main.js
const { app, BrowserWindow, Menu } = require('electron')
const {join} = require("path");
// 应用创建窗口
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: join(__dirname, 'preload.js')
}
})
// 设置窗口菜单
const menu = Menu.buildFromTemplate([
{
label: '设置',
submenu: [
{
// 点击+1按钮时触发update-counter事件并传递参数1
click: () => win.webContents.send('update-counter', 1),
label: '+1'
},
{
// 点击-1按钮时触发update-counter事件并传递参数-1
click: () => win.webContents.send('update-counter', -1),
label: '-1'
}
]
}
])
Menu.setApplicationMenu(menu)
win.loadFile('index.html')
win.webContents.openDevTools();
}
app.whenReady().then(() => {
createWindow()
})
preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
// 渲染进程监听update-counter事件
handleCounter: (callback) => ipcRenderer.on('update-counter', callback)
})
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>count:<span id="count">0</span></div>
<script>
const count = document.getElementById('count')
// 传入监听update-counter事件的回调函数
window.myAPI.handleCounter((event, value) => {
const num = Number(count.innerText)
count.innerText = num + value
})
</script>
</body>
</html>
运行结果如下
以上就是electron的进程间通信,欢迎大家在评论区留言指正,相互学习