进程间通信
为了将Electron的不同类型的进程桥接在一起,我们需要使用被称为预加载preload的脚本
可用的API | 详细信息 |
---|---|
Electron模块 | 渲染进程模块 |
Node.js模块 | events、timers、url |
Pollfilled的全局模块 | Buffer、process、clearImmediate、setImmediate |
preload脚本Demo
创建一个preload.js
然后在需要的进程里加载
注意:可以用的api在上面有说明, 在文档可以看一下这些模块有什么属性/方法: https://www.electronjs.org/zh/docs/latest/api/process#processversionschrome-%E5%8F%AA%E8%AF%BB
preload.js
const { contextBridge } = require('electron');
const versions = contextBridge.exposeInMainWorld('versions', {
node: process.versions.node,
chrome: process.versions.chrome,
electron: process.versions.electron
});
module.exports = versions;
在main文件中加载
const { app, BrowserWindow } = require('electron');
const path = require('path');
function createWindow () {
let win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
win.loadFile('index.html');
win.webContents.openDevTools();
return win;
}
注意: 在index.html页面,我们就可以使用window.versions来访问或执行对应的方法了
IPC通信
Electron 的 IPC(Inter-Process Communication,进程间通信)机制允许主进程和渲染进程之间的双向通信,是构建功能丰富的桌面应用的关键
- 主进程使用 ipcMain:监听和处理来自渲染进程的消息。]
- 渲染进程使用 ipcRenderer:向主进程发送消息或接收回复。
单向进程
主要两个方法
ipcRenderer.send(发送) 和ipcMain.on(接收)
demo: 修改窗口标题(单向进程)
index.html 的script
const demo2 = function() {
let btn = document.querySelector('.demo2 button');
let input = document.querySelector('.demo2 input');
btn.addEventListener('click', () => {
let title = input.value;
window.electron.setTitle(title)
})
}
preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electron', {
setTitle(title) {
return ipcRenderer.send('set-title', title)
}
})
main.js
const { app, BrowserWindow, ipcMain } = require('electron');
// ...
// app是BrowserWindow的一个实例
app.on('ready', () => {
let parent = createWindow();
// createChildWindow(parent);
ipcMain.on('set-title', (event, title) => {
console.log('title, ', title)
const webContents = event.sender;
// 获取渲染进程(当前渲染的窗口)实列
const win = BrowserWindow.fromWebContents(webContents);
// 修改窗口
win.setTitle(title);
})
})
ipcMain的event说明: https://www.electronjs.org/zh/docs/latest/api/structures/ipc-main-event
双向通信
双向通信 - 从渲染器进程到主进程,再从主进程到渲染进程
主要的两个方法: ipcRenderer.invoke(发送) 和ipcMain.handle(响应)
写法都差不多,调用的api不同,多了一个返回值而已
写入文件内容并响应(demo)
index.html
btn.addEventListener('click', async() => {
let content = input.value || 'string';
const size = await window.electron.handleWriteFile(content);
console.log('响应值', size )
})
preload.js
handleWriteFile(content) {
console.log('ipcrenderer')
console.log(content, 'content')
return ipcRenderer.invoke('write-file', content);
}
main.js
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
const fs = require('fs');
function createWindow () {
let win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
win.loadFile('index.html');
win.webContents.openDevTools();
return win;
}
app.on('ready', () => {
ipcMain.handle('write-file', async(event, content) => {
await fs.promises.writeFile('test.txt', content);
const textFile = await fs.promises.stat('test.txt');
// 主要是这里要响应,渲染进程就可以接收到了。
return textFile.size;
});
createWindow();
})
主进程向渲染进程通信
通过win.webContents.send();
main.js
const { app, BrowserWindow, ipcMain } = require('electron');
function createWindow () {
let win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
win.loadFile('index.html');
win.webContents.openDevTools();
return win;
}
app.on('ready', () => {
const win = createWindow();
let count = 0;
win.webContents.send('update-count', count);
setInterval(() => {
count++;
win.webContents.send('update-count', count);
}, 1000);
})
preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electron', {
updateCounter(callback) {
return ipcRenderer.on('update-count', callback)
}
})
index.html
window.electron.updateCounter((event, count) => {
console.log(count, 'count')
})