【问题标题】:Electron renderer.js listen app.js and preload.jsElectron renderer.js 监听 app.js 和 preload.js
【发布时间】:2022-03-08 05:56:45
【问题描述】:

我需要使用 preload.js 将 app.js 中的元素发送到 renderer.js (index.html),而不需要通过 renderer.js 调用函数。

有可能吗?

在 electron ipc 和 contextbridge 代码下方。

renderer.js

window.onload = () => {
  const counter = document.querySelector('h2');
  setInterval(() =>{
    api.get(counter.innerText).then(res => {
        counter.innerText = res
    })
  }, 1000)
}

preload.js

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

contextBridge.exposeInMainWorld('api', {
  get: arg => ipcRenderer.invoke('get', arg),
})

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')
    }
  })

  // ipc response on request
  ipcMain.handle('get', (event, arg) => {
    return ++arg
  })

  mainWindow.loadFile('index.html')

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

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>

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

【问题讨论】:

    标签: javascript node.js electron


    【解决方案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 函数。现在工作正常
    猜你喜欢
    • 2021-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-08
    • 2018-11-22
    • 1970-01-01
    • 1970-01-01
    • 2019-06-22
    相关资源
    最近更新 更多