六、进程通信
6.1 主进程与渲染进程之间的通信
有时候我们想在渲染进程中通过一个事件去执行主进程里面的方法。或者在渲染进程中通知 主进程处理事件,主进程处理完成后广播一个事件让渲染进程去处理一些事情。这个时候就 用到了主进程和渲染进程之间的相互通信
Electron
主进程,和渲染进程的通信主要用到两个模块: ipcMain
和 ipcRenderer
ipcMain
:当在主进程中使用时,它处理从渲染器进程(网页) 发送出来的异步和同步信息,当然也有可能从主进程向渲染进程发送消息。ipcRenderer
: 使用它提供的一些方法从渲染进程 (web
页面) 发送同步或异步的消息到主进程。 也可以接收主进程回复的消息
6.1.1 渲染进程给主进程发送异步消息
间接实现渲染进程执行主进程里面的方法
1. 引入 ipcRender
<!--src/index.html--> <button id="send">在 渲染进程中执行主进程里的方法(异步)</button> <script src="render/ipcRender.js"></script>
2. 引入 ipcMain
// 在主进程 src/index.js 中引入 const createWindow = () => { // 创建菜单 // 引入菜单模块 require('./main/ipcMain.js') };
3. 渲染进程发送消息
// src/render/ipcRender.js //渲染进程 let send = document.querySelector('#send'); const { ipcRenderer } = require('electron'); send.onclick = function () { // 传递消息给主进程 // 异步 ipcRenderer.send('sendMsg', {name:'poetries', age: 23}) }
2. 主进程接收消息
// src/main/ipcMain.js //主进程 const { ipcMain } = require('electron') // 主进程处理渲染进程广播数据 ipcMain.on('sendMsg', (event, data)=> { console.log('data\n ', data) console.log('event\n ', event) })
6.1.2 渲染进程发送消息,主进程接收消息并反馈
渲染进程给主进程发送异步消息,主进程接收到异步消息以后通知渲染进程
1. 引入 ipcRender
<!--src/index.html--> <button id="sendFeedback">在 渲染进程中执行主进程里的方法,并反馈给主进程(异步)</button> <script src="render/ipcRender.js"></script>
2. 引入 ipcMain
// 在主进程 src/index.js 中引入 const createWindow = () => { // 创建菜单 // 引入菜单模块 require('./main/ipcMain.js') };
3. 渲染进程发送消息
// src/render/ipcRender.js //渲染进程 let sendFeedback = document.querySelector('#sendFeedback'); const { ipcRenderer } = require('electron'); // 向主进程发送消息 sendFeedback.onclick = function () { // 触发主进程里面的方法 ipcRenderer.send('sendFeedback', {name:'poetries', age: 23}) }
4. 主进程收到消息处理并广播反馈通知渲染进程
// src/main/ipcMain.js //主进程 const { ipcMain } = require('electron') // 主进程处理渲染进程广播数据,并反馈给渲染进程 ipcMain.on('sendFeedback', (event, data)=> { // console.log('data\n ', data) // console.log('event\n ', event) // 主进程给渲染进程广播数据 event.sender.send('sendFeedbackToRender', '来自主进程的反馈') })
5. 渲染进程处理主进程广播的数据
// src/render/ipcRender.js // 向主进程发送消息后,接收主进程广播的事件 ipcRenderer.on('sendFeedbackToRender', (e, data)=>{ console.log('event\n ', e) console.log('data\n ', data) })
6.1.3 渲染进程给主进程发送同步消息
1. 引入 ipcRender
<!--src/index.html--> <button id="sendSync">渲染进程和主进程同步通信</button> <script src="render/ipcRender.js"></script>
2. 引入 ipcMain
// 在主进程 src/index.js 中引入 const createWindow = () => { // 创建菜单 // 引入菜单模块 require('./main/ipcMain.js') };
3. 渲染进程给主进程同步通信
// src/render/ipcMain.js let sendSync = document.querySelector('#sendSync'); // 渲染进程和主进程同步通信 sendSync.onclick = function () { // 同步广播数据 let msg = ipcRenderer.sendSync('sendsync', {name:'poetries', age: 23}) // 同步返回主进程反馈的数据 console.log('msg\n ', msg) }
4. 主进程接收数据处理
// src/main/ipcMain.js // 渲染进程和主进程同步通信 接收同步广播 ipcMain.on('sendsync', (event, data)=> { // console.log('data\n ', data) // console.log('event\n ', event) // 主进程给渲染进程广播数据 event.returnValue ='渲染进程和主进程同步通信 接收同步广播,来自主进程的反馈.'; })
6.1.4 渲染进程广播通知主进程打开窗口
一般都是在渲染进程中执行广播操作,去通知主进程完成任务
1. 引入 openWindow
<!--src/index.html--> <button id="sendSync">渲染进程和主进程同步通信</button> <script src="render/openWindow.js"></script>
2. 引入 ipcMain2
// 在主进程 src/index.js 中引入 const createWindow = () => { // 创建菜单 // 引入菜单模块 require('./main/ipcMain2.js') };
3. 渲染进程通知主进程打开窗口
// src/render/openWindow.js /* eslint-disable */ let openWindow = document.querySelector('#openWindow'); var { ipcRenderer } = require('electron'); // 渲染进程和渲染进程直接的通信======== openWindow.onclick = function () { // 通过广播的形式 通知主进程执行操作 ipcRenderer.send('openwindow', {name:'poetries', age: 23}) }
4. 主进程收到通知执行操作
// src/main/ipcMain2.js /* eslint-disable */ let { ipcMain,BrowserWindow } = require('electron') const path = require('path') let win; // 接收到广播 ipcMain.on('openwindow', (e, data)=> { // 调用 window 打开新窗口 win = new BrowserWindow({ width: 400, height: 300, }); win.loadURL(path.join('file:',__dirname, '../news.html')); win.webContents.openDevTools() win.on('closed', () => { win = null; }); })
6.2 渲染进程与渲染进程之间的通信
也就是两个窗口直接的通信
6.2.1 localstorage 传值
Electron
渲染进程通过 localstorage
给另一个渲染进程传值
1. 引入 openWindow
<!--src/index.html--> <button id="sendSync">渲染进程和主进程同步通信</button> <script src="render/openWindow.js"></script>
2. 引入 ipcMain2
// 在主进程 src/index.js 中引入 const createWindow = () => { // 创建菜单 // 引入菜单模块 require('./main/ipcMain2.js') };
3. 渲染进程通知主进程打开窗口
// src/render/openWindow.js /* eslint-disable */ let openWindow = document.querySelector('#openWindow'); var { ipcRenderer } = require('electron'); // 渲染进程和渲染进程直接的通信======== openWindow.onclick = function () { // 通过广播的形式 通知主进程执行操作 ipcRenderer.send('openwindow', {name:'poetries', age: 23}) // ======= localstorage 传值 ===== localStorage.setItem('username', 'poetries') }
4. 新建 news 页面
<!--src/news.html--> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> news page </body> <script src="render/news.js"></script> </html>
// src/render/news.js let username = localStorage.getItem('username') console.log(username)
5. 主进程收到通知执行操作
// src/main/ipcMain2.js /* eslint-disable */ let { ipcMain,BrowserWindow } = require('electron') const path = require('path') let win; // 接收到广播 ipcMain.on('openwindow', (e, data)=> { // 调用 window 打开新窗口 win = new BrowserWindow({ width: 400, height: 300, }); win.loadURL(path.join('file:',__dirname, '../news.html')); win.webContents.openDevTools() win.on('closed', () => { win = null; }); })
6.2.2 BrowserWindow 和 webContents 方式实现
通过 BrowserWindow
和 webContents
模块实现渲染进程和渲染进程的通信
webContents
是一个事件发出者.它负责渲染并控制网页,也是 BrowserWindow
对象的属性
需要了解的几个知识点
- 获取当前窗口的
id
const winId = BrowserWindow.getFocusedWindow().id;
- 监听当前窗口加载完成的事件
win.webContents.on('did-finish-load',(event) => { })
- 同一窗口之间广播数据
win.webContents.on('did-finish-load',(event) => { win.webContents.send('msg',winId,'我是 index.html 的数据'); })
- 通过
id
查找窗口
let win = BrowserWindow.fromId(winId);
下面是具体演示
1. 引入 openWindow
<!--src/index.html--> <button id="sendSync">渲染进程和主进程同步通信</button> <script src="render/openWindow.js"></script>
2. 引入 ipcMain2
// 在主进程 src/index.js 中引入 const createWindow = () => { // 创建菜单 // 引入菜单模块 require('./main/ipcMain2.js') };
3. 渲染进程通知主进程打开窗口
// src/render/openWindow.js /* eslint-disable */ let openWindow = document.querySelector('#openWindow'); var { ipcRenderer } = require('electron'); // 渲染进程和渲染进程直接的通信======== openWindow.onclick = function () { // 通过广播的形式 通知主进程执行操作 ipcRenderer.send('openwindow', {name:'poetries', age: 23}) }
4. 主进程收到通知执行操作
// src/main/ipcMain2.js let { ipcMain,BrowserWindow } = require('electron') const path = require('path') let win; // 接收到广播 ipcMain.on('openwindow', (e, userInfo)=> { // 调用 window 打开新窗口 win = new BrowserWindow({ width: 400, height: 300, }); win.loadURL(path.join('file:',__dirname, '../news.html')); // 新开窗口调试模式 win.webContents.openDevTools() // 把渲染进程传递过来的数据再次传递给渲染进程 news // 等待窗口加载完 win.webContents.on('did-finish-load', ()=>[ win.webContents.send('toNews', userInfo) ]) win.on('closed', () => { win = null; }); })
5. news 接收主进程传递的数据
数据经过渲染进程->主进程-> news
渲染进程
<!--news 页面--> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> news page </body> <script src="render/news.js"></script> </html>
// src/render/news.js var { ipcRenderer } = require('electron'); // let username = localStorage.getItem('username') // console.log(username) // 监听主进程传递过来的数据 ipcRenderer.on('toNews',(e, userInfo)=>{ console.log(userInfo) })
那么,这里有一个问题, news
进程接收到了广播后如何给出反馈呢?
1. 在主进程中获取窗口 ID 传递
// src/main/ipcMain2.js let { ipcMain,BrowserWindow } = require('electron') const path = require('path') let win; // 接收到广播 ipcMain.on('openwindow', (e, userInfo)=> { // 获取当前窗口 ID 放在第一行保险 因为后面也打开了新窗口使得获取的 ID 有问题 let winId = BrowserWindow.getFocusedWindow().id // 调用 window 打开新窗口 win = new BrowserWindow({ width: 400, height: 300, }); win.loadURL(path.join('file:',__dirname, '../news.html')); // 新开窗口调试模式 win.webContents.openDevTools() // 把渲染进程传递过来的数据再次传递给渲染进程 news // 等待窗口加载完 win.webContents.on('did-finish-load', ()=>[ win.webContents.send('toNews', userInfo, winId) ]) win.on('closed', () => { win = null; }); })
2. 在 news 进程中广播数据
// src/render/news.js var { ipcRenderer } = require('electron'); // 注意这里 在渲染进程中需要从 remote 中获取 BrowserWindow const BrowerWindow = require('electron').remote.BrowserWindow; // let username = localStorage.getItem('username') // console.log(username) // 监听主进程传递过来的数据 ipcRenderer.on('toNews',(e, userInfo, winId)=>{ // windID 第一个窗口 ID // 获取对应 ID 的窗口 let firstWin = BrowerWindow.fromId(winId) firstWin.webContents.send('toIndex', '来自 news 进程反馈的信息') console.log(userInfo) })
3. 在另一个渲染进程中处理广播
/* eslint-disable */ let openWindow = document.querySelector('#openWindow'); var { ipcRenderer } = require('electron'); // 渲染进程和渲染进程直接的通信======== openWindow.onclick = function () { // 传递消息给主进程 ipcRenderer.send('openwindow', {name:'poetries', age: 23}) // 传递给打开的窗口 渲染进程和渲染进程直接的通信 localStorage.setItem('username', 'poetries') } // 接收 news 渲染进程传递回来的消息 ipcRenderer.on('toIndex', (e, data)=>{ console.log('===', data) })
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论