返回介绍

六、进程通信

发布于 2024-09-07 18:20:40 字数 12718 浏览 0 评论 0 收藏 0

6.1 主进程与渲染进程之间的通信

有时候我们想在渲染进程中通过一个事件去执行主进程里面的方法。或者在渲染进程中通知 主进程处理事件,主进程处理完成后广播一个事件让渲染进程去处理一些事情。这个时候就 用到了主进程和渲染进程之间的相互通信

Electron 主进程,和渲染进程的通信主要用到两个模块: ipcMainipcRenderer

  • 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 方式实现

通过 BrowserWindowwebContents 模块实现渲染进程和渲染进程的通信

webContents 是一个事件发出者.它负责渲染并控制网页,也是 BrowserWindow 对象的属性

需要了解的几个知识点

  1. 获取当前窗口的 id
const winId = BrowserWindow.getFocusedWindow().id;
  1. 监听当前窗口加载完成的事件
win.webContents.on('did-finish-load',(event) => {
  
})
  1. 同一窗口之间广播数据
win.webContents.on('did-finish-load',(event) => {
  win.webContents.send('msg',winId,'我是 index.html 的数据');
})
  1. 通过 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文