VueJS 从 ipcRenderer (ElectronJS) 获取 "undefined" 数据

VueJS getting "undefined" data from ipcRenderer (ElectronJS)

当试图从 ipcMainipcRenderer 获取消息时(没有节点集成和 contextIsolation),它被接收但作为 undefined。不仅如此,如果我要重新加载 VueComponent(不管我对它做了什么更改),响应的数量都会翻倍。

例如,我第一次启动我的应用程序时,每次单击按钮时都会得到 1x undefined。如果我重新加载组件,每次单击按钮时我都会开始获得 2x undefined。每次我单击按钮时,我再次重新加载并获得 4x undefined...并且它一直在加倍。如果我重新启动应用程序,它会回到 1x。

设置

ElectronJS + VueJS + VuetifyJS 已按所述设置 here

preload.js 根据 official documentation.

import { contextBridge, ipcRenderer } from 'electron'
window.ipcRenderer = ipcRenderer

// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld('ipcRenderer', {
  send: (channel, data) => {
    // whitelist channels
    let validChannels = ['toMain']
    if (validChannels.includes(channel)) {
      ipcRenderer.send(channel, data)
    }
  },
  receive: (channel, func) => {
    let validChannels = ['fromMain']
    if (validChannels.includes(channel)) {
      // Deliberately strip event as it includes `sender`
      ipcRenderer.on(channel, (event, ...args) => func(...args))
    }
  }
})

background.js(主进程)根据 preload.js 文件的 official documentation...省略的代码是创建时生成的默认项目代码。

...

const path = require('path')
const { ipcMain } = require('electron')

async function createWindow() {
  // Create the browser window.
  const win = new BrowserWindow({

    width: 800,
    height: 600,
    webPreferences: {
      
      // Use pluginOptions.nodeIntegration, leave this alone
      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
      nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
      contextIsolation: true,
      preload: path.join(__dirname, 'preload.js'),
    },
    icon: 'src/assets/icon.png',
  })

  ipcMain.on('toMain', (event, data) => {
    console.log(data)
    event.sender.send('fromMain', 'Hello IPC Renderer')
    // The two lines below return 'undefined' as well in the 'ipcRenderer'
    //win.webContents.send('fromMain', "Hello IPC Renderer")
    //event.reply('fromMain', 'Hello IPC Renderer')
  })

  ...
}

...

vue.config.js 文件:

module.exports = {
  ...
  pluginOptions: {
    electronBuilder: {
      preload: 'src/preload.js',
    }
  }
}

main.js(渲染器进程)仅包含创建时生成的默认项目代码。

VueComponent.vue

<template>
  <div id="vue-component">
    <v-btn @click="sendMessageToIPCMain()">
  </div>
</template>

<script>
export default {
  name: "VueComponent",
  components: {
    //
  },
  data: () => ({
    myData: null,
  }),
  methods: {
    // This works. I get 'Hello IPC Main' in the CMD console.
    sendMessageToIPCMain() {
      var message = "Hello IPC Main"
      window.ipcRenderer.send("toMain", message);
    }
  },
  mounted() {
    window.ipcRenderer.receive('fromMain', (event, data) => {
      // this.myData = data // 'myData' is not defined error
      this.$refs.myData = data;
      console.log('myData variable: ' + this.$refs.myData) // undefined
      console.log(data) // undefined
    })
  },
}
</script>

VueComponent.vuemounted() 已按 here 所述设置,但如果我尝试使用 [=28= 将 data 发送到变量], 我收到一条错误消息,指出 myData 尚未定义 - 使用 this.$refs.myData 有效,尽管它仍然是 undefined.

P.S。 myData 尚未定义错误 =/= 未定义。前者是红色字体的正确错误,而后者如上图所示。

为了解决第一个问题(函数调用加倍),您必须删除 window.ipcRenderer = ipcRenderer。在 contextIsolation 模式下,方法是仅使用 contextBridge.exposeInMainWorld() 。使用这两种实现肯定会导致问题。

对于第二个问题,ipcRenderer 中对 receive 的回调仅使用来自 main 的 ...args 调用(没有事件传递给 func)。见:

ipcRenderer.on(channel, (event, ...args) => func(...args)) <-- func() is called with only args

你唯一应该改变的是你的函数在挂载中,只接受数据:

window.ipcRenderer.receive('fromMain', (data) => {
  console.log(data) // should log you data
})