【解决方案1】:

目前,您的preload.js 脚本仅配置为使用ipcRender.invoke(),该ipcRender.invoke() 用于渲染线程主线程然后再返回到渲染线程。

如果你想主线程渲染线程,那么你需要使用contents.send(channel, ...args)

例如:mainWindow.webContents.send('channel', 'message');.

要实现“关注点分离”并将硬编码函数排除在 preload.js 脚本之外,您可以重构您的 preload.js 脚​​本,使其仅反映您列入白名单的“通道”和相关的传输方法。这也大大提高了可读性。

请参阅下面的代码,了解对初始 IPC 调用函数调用、主线程实现以呈现线程 IPC 和新的 `preload.js 文件的更改。


index.html(渲染线程)

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
        <title>IPC Example</title>
    </head>

    <body>
        <h1>Wait on response...</h1>
        <h2>0</h2>
    </body>

    <script src="./renderer.js"></script>
</html>

当您将&lt;script&gt; 标记放在html 文档的底部而不是&lt;head&gt; 标记中时,window.onload 的使用就变得多余了。

render.js(渲染线程)

const counter = document.querySelector('h2');

// IIFE - Immediately Invoked Function Expression
(function() {
    // Let's run the counter function.
    counter();

    // Listen on this channel for an incoming test.
    window.ipcRender.receive('channel:test', (message) => {
        console.log(message);
    });
})();

// 
function counter() {
    setInterval(() => {
        window.ipcRender.invoke('channel:count', counter.innerText)
            .then((result) => {
                counter.innerText = result;
            })
    }, 1000);
}

preload.js(主线程)

const {contextBridge, ipcRenderer} = require('electron');

// White-listed channels.
const $ipc = {
    'render': {
        // From render to main.
        'send': [],
        // From main to render.
        'receive': [
            'channel:test'
        ],
        // From render to main and back again.
        'sendReceive': [
            'channel:count'
        ]
    }
};

// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
    // Allowed 'ipcRenderer' methods.
    'ipcRender', {
        // From render to main.
        send: (channel, args) => {
            let validChannels = $ipc.render.send;
            if (validChannels.includes(channel)) {
                ipcRenderer.send(channel, args);
            }
        },
        // From main to render.
        receive: (channel, listener) => {
            let validChannels = $ipc.render.receive;
            if (validChannels.includes(channel)) {
                // Deliberately strip event as it includes `sender`.
                ipcRenderer.on(channel, (event, ...args) => listener(...args));
            }
        },
        // From render to main and back again.
        invoke: (channel, args) => {
            let validChannels = $ipc.render.sendReceive;
            if (validChannels.includes(channel)) {
                return ipcRenderer.invoke(channel, args);
            }
        }
    }
);

app.js(主线程)

const {app, BrowserWindow, ipcMain} = require('electron');

const path = require('path');

app.whenReady().then(() => {
    const mainWindow = new BrowserWindow({
        width: 500,
        height: 500,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js')
        }
    })

    mainWindow.loadFile('index.html');

    // Open the DevTools.
    // mainWindow.webContents.openDevTools();

    // ipc from render to main and back again.
    ipcMain.handle('channel:count', (event, count) => {
        return ++count;
    })

    // ipc from main to render.
    mainWindow.webContents.send('channel:test', 'This is a test');
})

【讨论】:

  • 感谢我使用mainWindow.webContents.send('channel', 'message')的答案
  • @Aaqu 如果这回答了您的问题,那么您可以通过单击答案顶部的赞成/反对票图标下方的灰色勾号图标来接受答案。如果它没有回答您的问题,请告诉我您需要哪些其他信息/帮助。
  • 我没有足够的声望来添加向上箭头,抱歉
  • 我在 preload.js 中添加了两个小改动,将 ipcRenderer 改为 ipcRenderer,并重命名了 counter 函数。现在工作正常