VueJS 从 ipcRenderer (ElectronJS) 获取 "undefined" 数据
VueJS getting "undefined" data from ipcRenderer (ElectronJS)
当试图从 ipcMain
到 ipcRenderer
获取消息时(没有节点集成和 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.vue
的 mounted()
已按 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
})
当试图从 ipcMain
到 ipcRenderer
获取消息时(没有节点集成和 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.vue
的 mounted()
已按 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
})