封装一个 renderer 之间通信的 class

electron 中的渲染进程之间是无法直接通信的,需要借助 主进程 作为中间商 来进行通信,因此我们可以去封装一个 class 来实现这个效果,这样方便我们调用

假设我们现在有多个 webview,比如 library,shop,popup ......

我们可以封装一个 ipcService 类放到 utils 中去,既然是本质是借助 main 主进程去作中间商,那么还是让 preload 去 send 事件 给到 main,main 去 on 监听即可

我希望有个方法 sendToTarget 可以 传入 指定具体的 webview,第二个参数为一个事件,第三个参数给一个 ...args 即可

那么调用的形式就应该是

js 复制代码
ipcService.sendToTarget('library', 'gameStarted', gameData)

我在 library 里面接收那么 希望 有个 onMessage,那就

js 复制代码
ipcService.onMessage('gameStarted', (gameData) => {
  // 处理游戏启动事件
})

函数名,入参以及如何使用确定了,现在动手实现,先看 sendToTarget

sendToTarget 自然需要将这个事件以及参数传递给 main

那么就需要我们在 preload 中抛出一个对象 electronAPI(名称自定义),让 render 调用 electronAPI 上的方法去告诉 main 即可

preload.js 复制代码
const { contextBridge, ipcRenderer } = require('electron') 

contextBridge.exposeInMainWorld('electronAPI', {
	send: (channel, ...args) => {
		ipcRenderer.send(channel, ...args)
	}
})

这样,我们就可以确定 ipcService.sendToTarget 如何 实现了

js 复制代码
class IpcService {
  constructor() {
    if (!window.electronAPI) {
      console.error('electronAPI 未初始化,请确保在 preload 脚本中正确配置');
    }
  }
    
  sendToTarget (targetKey, event, ...args) {
      window.electronAPI.send('webView:postMessage', targetKey, event,  ...args)
  }
}

于是我们在 main 中监听 webView:postMessage 事件并转发即可

在 main 中,通常会有个 webContentsManager.js 去集中管理 webview 的生命周期,我们可以将 webView:postMessage 的监听并转发在这里实现

js 复制代码
const { app, ipcMain, WebContents, screen } = require('electron')

class WebContentsManager {
    initIpc () {
        ipcMain.on ('webView:postMessage', (_, key, ...args) => {
            const win = this.getWindow(key)
		   if (!win) return 
            win.webContents.send('webView:postMessage', ...arg)
        })
    }
}

win.webContents.send() 就是 main 向 render 通信的方法

这里我们需要通过 key 拿到具体的 win,至于如何 getWindow ,这里我们可以选择 用 map 去存 webview,因此 this.webViewMap.get(key) 就能拿到 具体的 win

main send 来 webView:postMessage 事件后,我们就需要在 preload 的 electronAPI 中去 on 这个事件,onMessage 接收肯定需要一个回调来拿到 这个 ...args

js 复制代码
const { contextBridge, ipcRenderer } = require('electron') 

contextBridge.exposeInMainWorld('electronAPI', {
	send: (channel, ...args) => {
		ipcRenderer.send(channel, ...args)
	}
    
    receive: (channel, ...args) => {
    	ipcRenderer.on(channel, (event, ...args) => callback(...args))
	}
})

接下来实现 ipcService.onMessage()

js 复制代码
class IpcService {
  constructor() {
    if (!window.electronAPI) {
      console.error('electronAPI 未初始化,请确保在 preload 脚本中正确配置');
    }
  }
    
  sendToTarget (targetKey, event, ...args) {
      window.electronAPI.send('webView:postMessage', targetKey, event,  ...args)
  }
    
  onMessage (event, callback) {
      window.electronAPI.receive('webView:postMessage', (receivedEvent, ...args) => {
          if (receivedEvent === event) {
              callback(...args)
          }
      })
  }
}

const ipcService = new IpcService();

export { ipcService };

receivedEvent === event 是为了防止多个事件混淆,比如这里的我们传入的是 gameStarted,也有可能会有其他的事件

至此,这样一个 ipcService 就封装完毕了

相关推荐
瑞瑞小同学35 分钟前
处理echarts x轴内容过多,重叠问题
前端·javascript·echarts
HexCIer42 分钟前
面向未来的原子化 CSS:UnoCSS 核心架构分析与 Tailwind CSS 现状
前端·css·vite
程序员黑豆1 小时前
鸿蒙应用开发中的单位详解:px、vp、fp、lpx
前端·harmonyos
像我这样帅的人丶你还1 小时前
MCP + npm:给五年前的老系统接上AI
前端·javascript·agent
南一Nanyi2 小时前
依赖注入和控制反转
前端·设计模式·nestjs
小村儿2 小时前
连载14-实战篇--一个半月,我一个人和 Claude Code 搭出一套数字人工程
前端·后端·ai编程
愚公移码2 小时前
蓝凌EKP18产品:流程虚拟机(PVM)
java·开发语言·前端
promiseThen2 小时前
5 分钟上手 Markdown:标题到表格、代码块与简历实战
前端
web66liang2 小时前
webpack4+vue2项目使用 sass-embedded 导致的 DockerfIle 构建失败的问题
前端
Strayer2 小时前
拓扑管网 3D 可视化大屏demo:科技感(地图 + 拓扑 + 3D 空间)
前端·three.js·数据可视化