Electron 的通讯机制

Electron 在运行时分为主进程渲染器进程(渲染进程),主进程可以用NodeJS的 api,渲染进程可以用浏览器的 api

两者之间需要通过 Electron 提供的 api 来通讯

渲染进程

首先需要在渲染进程设置一个监听器,用来监听主进程发来的消息

然后主动发送一个消息给主进程

1
2
3
4
5
6
7
8
9
// 监听器
ipcRenderer.on('mainSend', (event, message) => {
console.log('主进程发来的消息', message)
})

// 在合适的地方发送给主进程,比如按钮点击事件中
button.onclick = function() {
ipcRenderer.send('rendererSend', 'xxx')
}

主进程

接下来是主进程中,需要创建一个监听器,用来监听渲染进程发过来的消息

1
2
3
4
5
6
7
ipcMain.on('rendererSend', (event, path) => {
// 这里是主进程的处理,比如渲染进程发来的是一个文件路径
// 主进程可以调用 NodeJs 的 api
fs.unlink(path)
// 删除后在告诉渲染进程已经删掉了
event.sender.send('mainSend', `${path} 已删除`)
})

至此,渲染进程的监听器mainSend会接收到消息,xxx 已删除

带来的问题

个人感觉这种写法比较难受,因为我加一个通讯,就得写一遍上述内容

最少的情况也是主进程渲染进程各要写一个,最后会有大量的onsend

electron-vue-event-manager

于是解决方案出现了,electron-vue-event-manager是个基于electron-vue的事件管理器

可以让你在任意地方创建监听器,在任意地方触发它(发起广播)

它能解决如下问题

  • 主进程渲染进程通信
  • 渲染进程自身的通信 (同一窗口内Vue组件之间)
  • 渲染进程其他渲染进程通信 (不同窗口之间)

初始化

既然每个通信都需要一个on和一个send,那其实我只需创建一次

再通过不同的参数区分具体是什么通讯,不就解决了每种通讯要创建一个onsend的问题了

electron-vue-event-manager的解决方案正是如此,在主进程渲染进程中调用各自的初始化函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 主线程 (需要把所有创建的窗口传进去)
EventManager.Instance().mainInit([
{
// 创建的窗口,类型 BrowserWindow
window: window1,
// 类型,唯一标示
type: 'window1'
},
{
window: window2,
type: 'window2'
}
])

// 渲染进程
EventManager.Instance().rendererInit()

监听器

然后就可以在任何地方写一个监听器,比如下面这个是在渲染进程中,Vue的某个页面的created生命周期中

1
2
3
4
5
6
7
8
9
10
// Window2 添加监听事件
EventManager.Instance().addEventListener<string>(
// 事件类型 (string)
EventType.Window1SendMessage,
// 接收到广播后的回调函数
(window1Message) => {
this.message = window1Message
console.log('接收到来自 Window1 的消息:', window1Message)
}
)

广播

广播指的是调用监听器,监听器可以有多个,相当于收音机,所以调用这个动作叫做广播

以下是在另一个渲染进程

1
2
3
4
5
6
7
// Window1 进行广播
EventManager.Instance().broadcast<string>(
// 事件类型 (string)
EventType.Window1SendMessage,
// 参数 (输入框内容)
this.inputValue
)

实际应用

以上的代码实际应用如下图,你可以从Window1发送消息给Window2

也可以在Vue组件之间传递

网络请求

除了跨窗口、跨组件通信之外,还有网络请求是需要封装的

因为渲染进程是个浏览器窗口,发起网络请求也就会有跨域问题

所以你需要先让渲染进程把请求相关的数据发给主进程,再由主进程发起网络请求,拿到数据后发回渲染进程

electron-vue-event-manager基于axios封装好了一个方法,可以在任何地方调用即可发起网络请求

1
2
3
4
5
6
7
8
EventManager.Instance().sendRequest({
url: 'Request URL',
method: 'POST'
}).then(data => {
console.log(data)
})

// EventManager.Instance().sendRequest(options) === axios(options).then(response => response.data)

使用

当前

1.0.0之前为自用版,因为还有很多没完善

目前能做到像上述的功能一样,但可能存在问题,谨慎使用

你可以在 GithubNpmjs 获取到更多信息