通过 Electron IPCmain 通道向 vue 实例发送消息只能以一种方式工作

Sending messages through Electron IPCmain channel to vue instance only works one way

我正在尝试在主电子进程和 vue 实例之间来回发送消息。到目前为止我所拥有的是

Preload.js:

import { contextBridge, ipcRenderer } from 'electron'
window.addEventListener('DOMContentLoaded', () => {
    const replaceText = (selector, text) => {
        const element = document.getElementById(selector)
        if (element) element.innerText = text
    }

    for (const dependency of ['chrome', 'node', 'electron']) {
        replaceText(`${dependency}-version`, process.versions[dependency])
    }

})
window.ipcRenderer = require('electron').ipcRenderer;

contextBridge.exposeInMainWorld('ipcRenderer', {
    //Render (Vue) to main (Electron)
    send: (channel, data) => {
        let validChannels = ['clientMessage'] // <-- Array of all ipcRenderer Channels used in the client
        if (validChannels.includes(channel)) {
            ipcRenderer.send(channel, data)
        }
    },
    //Main (Electron) to Render (Vue)
    on: (channel, func) => {
        let validChannels = ['electronMessage'] // <-- Array of all ipcMain Channels used in the electron
        if (validChannels.includes(channel)) {
            // Deliberately strip event as it includes `sender`
            ipcRenderer.on(channel, (event, ...args) => func(...args))
        }
    }
})

所以我在 ipcRender 中有 2 个白名单通道,一个叫做 'clientMessage' 从 vue 实例发送消息到电子主进程,另一个是 'electronMessage' 从电子主进程发送消息处理到 vue 实例。

在我的 background.js 中,我有以下内容:

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

ipcMain.on('clientMessage', (event, args) => {
 console.log('received a message from vue: '+args)
  event.sender.send('message','return Message from electron'+args);
});

在我的 app.Vue 中我有:

mounted () {
    window.ipcRenderer.on('electronMessage', (event, data) => {
      console.log('message from electron: '+data)
    })
  },
  methods: {
    sendMessage(){
      window.ipcRenderer.send('clientMessage','testing')
    }
  }

该应用程序运行良好,当我调用 sendMessage 函数时,我在电子终端上正确地获得了一个控制台日志,提示已收到消息。很明显 vue -> electron messaging 有效,但为什么它不能用于相反的情况?

您的contextBridge.exposeInMainWorld“键”是ipcRenderer.sendipcRenderer.receive

您必须使用这些键来访问您定义的 preload.js IPC 方法。即:sendon.

具体来说,要使用 ipcRender.on(...) 方法,您可以使用 window.ipcRenderer.receive(...) 调用它。

app.Vue(渲染线程)

// To send a message from render thread to main thread.
window.ipcRenderer.send('clientMessage','testing'); // Working

// To receive a message from main thread to render thread.
window.ipcRenderer.receive('electronMessage', (event, data) => {
    console.log('message from electron: ' + data);
});

我知道为什么了,从electron主进程向renderer实例发送消息的方式不一样。由于始终只有一个 electron 主进程 运行,我们可以在 vue 渲染器实例中简单地执行 window.ipcRenderer.send('', 'your message'),但由于可以有多个渲染器实例 运行,主电子进程需要知道将其发送到哪个渲染进程。

所以在你的 main.js/background.js 中不管你是什么 .js 运行 electron 主进程。这样做:

let win;

async function createWindow() {
  // Create the browser window.
  win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: true,
      enableRemoteModule: true,
      preload: path.join(__dirname, "preload.js")
    }
  })
.
.
.

然后向渲染实例发送消息:

win.webContents.send('<channelName>','your message')

以这种方式将其发送到正确的渲染进程。所以我的代码最后看起来是这样的:

ipcMain.on('clientMessage', (event, args) => {
 console.log('received a message from vue: '+args)
 win.webContents.send('electronMessage','Reply from main process: '+args)
});