如何将渲染进程信息给主进程

万能的方法ipcMain.handle(channel,listener)

异步同步均可,异步async/await等等计算,返回promise,同步写也可

  • Main Process(主进程)
//my-invokable-ipc随便取的名字
//

ipcMain.handle('my-invokable-ipc', async (event, ...args) => {
const result = await somePromise(...args)
return result
})
  • Renderer Process(渲染进程)
async () => {
const result = await ipcRenderer.invoke('my-invokable-ipc', arg1, arg2)
// ...
}

实现

  • 根目录html
  • script放在title后会导致JavaScript语法报错,因为还没有渲染完

script_error

  • 得放在/body前,html标签下,如下面的代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!--配置CSP-->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src 'self' data:;
script-src 'self'; style-src 'self' 'unsafe-inline'">
<title>Document</title>

</head>
<body>
hello
<button id="btn">点击</button>

<script src="./render/app.js"></script>
</body>
</html>
  • render文件夹里的app.js
document.querySelector('#btn').addEventListener('click', () => {
console.log(0)
})

  • preload.js
const { contextBridge,ipcMain } = require('electron')
//myApi是接口(任意取),后面是接口里的值
contextBridge.exposeInMainWorld('myApi', {
platform : process.platform,
desktop: true
})

ipcMain.handle('send-event',()=>{
return
})
  • 出现报错,因为preload没有获取到ipcMain

preload_error

  • 先不要在这写

  • preload.js改后

const { contextBridge,ipcMain } = require('electron')
//myApi是接口(任意取),后面是接口里的值
contextBridge.exposeInMainWorld('myApi', {
platform : process.platform,
desktop: true
})

ipcMain.handle('send-event',()=>{
return
})
  • 在入口文件main.js的主进程写

  • 代码

const { app, BrowserWindow,ipcMain } = require('electron')

// 监听只有一次,不能每次窗口打开就再次监听吧

ipcMain.handle('send-event',(event,msg)=>{
console.log(msg)
})

  • 具体位置
const path = require('path')
const { app, BrowserWindow,ipcMain } = require('electron')
// 主进程
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// dirname当前入口文件的绝对物理路径+相对路径
preload: path.resolve(__dirname, './preload.js')
}
})
win.loadFile('./index.html')
// win.loadURL('./index.html')
// 打开开发者工具
win.webContents.openDevTools()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length == 0) {
createWindow()
}
})
}

app.on('window-all-closed', () => {
if (process.platform == 'darwin') {
app.quit()
}
})
// 监听只有一次,不能每次窗口打开就再次监听吧
ipcMain.handle('send-event',(event,msg)=>{
console.log(msg)
})

app.whenReady().then(createWindow)


  • 渲染进程点击,调用主线程函数
  • ipcRenderer渲染函数可以在preload.js

完整

  • preload.js 挂载,渲染
const { contextBridge, ipcRenderer } = require('electron')

const handleSend = () => {
ipcRenderer.invoke('send-event', 'hahaha')
}

//myApi是接口(任意取),后面是接口里的值
contextBridge.exposeInMainWorld('myApi', {
platform: process.platform,
handleSend
// desktop: true
})

  • app.js 调用ipcMain 中的函数名myApi的属性
// console.log('100')
document.querySelector('#btn').addEventListener('click', () => {
//window可写可不写
myApi.handleSend()
})

  • main.js 引入ipcMain
const path = require('path')
const { app, BrowserWindow, ipcMain } = require('electron')
// 主进程
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// dirname当前入口文件的绝对物理路径+相对路径
preload: path.resolve(__dirname, './preload.js')
}
})
win.loadFile('./index.html')
// win.loadURL('./index.html')
// 打开开发者工具
win.webContents.openDevTools()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length == 0) {
createWindow()
}
})
}

app.on('window-all-closed', () => {
if (process.platform == 'darwin') {
app.quit()
}
})

app.whenReady().then(createWindow)
// 监听只有一次,不能每次窗口打开就再次监听吧
ipcMain.handle('send-event', (event, msg) => {
console.log(msg)
})

  • html引入./render/app.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!--配置CSP-->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src 'self' data:;
script-src 'self'; style-src 'self' 'unsafe-inline'">
<title>Document</title>
</head>
<body>
hello
<button id="btn">点击</button>
<script src="./render/app.js"></script>
</body>
</html>
  • 点击出现在,终端里

result


  • 要返回到,浏览器即页面上,只修改入口文件main.js和预加载文件preload.js,这两个

  • main.js ipcMain写return回去

const path = require('path')
const { app, BrowserWindow, ipcMain } = require('electron')
// 主进程
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// dirname当前入口文件的绝对物理路径+相对路径
preload: path.resolve(__dirname, './preload.js')
}
})
win.loadFile('./index.html')
// win.loadURL('./index.html')
// 打开开发者工具
win.webContents.openDevTools()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length == 0) {
createWindow()
}
})
}

app.on('window-all-closed', () => {
if (process.platform == 'darwin') {
app.quit()
}
})

app.whenReady().then(createWindow)
// 监听只有一次,不能每次窗口打开就再次监听吧
ipcMain.handle('send-event', (event, msg) => {
return msg
})

  • preload.js 修改成异步
const { contextBridge, ipcRenderer } = require('electron')

const handleSend = async () => {
let fallback = await ipcRenderer.invoke('send-event', 'hahaha')
console.log(fallback)
}

//myApi是接口(任意取),后面是接口里的值
contextBridge.exposeInMainWorld('myApi', {
platform: process.platform,
handleSend
// desktop: true
})

  • 点击后,就会出现在网页里的

result

总结

触发:渲染进程调用preload.js里的ipcRenderer函数,preload调用mian里的ipcMain函数

接收:preload调用mian里的ipcMain函数return,渲染进程调用preload.js里的ipcRenderer函数,async/await异步接收promise对象