为了账号安全,请及时绑定邮箱和手机立即绑定

使用前端 javascript 文件中的电子 ipcRenderer

使用前端 javascript 文件中的电子 ipcRenderer

拉莫斯之舞 2022-10-08 15:20:58
我正在学习使用 Electron,在尝试让我的应用程序与前端通信时,我知道我需要使用ipcRenderer来获取对 DOM 元素的引用,然后将该信息传递给ipcMain.我尝试遵循此处和此处建议的大部分建议,但是这两个示例都使用require('electron').ipcMain,并且每当我尝试将与前端交互的脚本包含到我的 HTML 中时,自Uncaught ReferenceError: require is not defined. 我一直在寻找几个小时,并没有找到解决方案的运气 - 很明显我做错了什么。我main.js的很简单,我只是创建了我的窗口,然后我创建了一个 ipc 侦听器,如下所示:const { app, BrowserWindow } = require("electron");const ipc = require('electron').ipcMain;function createWindow() {    const window = new BrowserWindow({        transparent: true,        frame: false,        resizable: false,        center: true,        width: 410,        height: 550,    });    window.loadFile("index.html");}app.whenReady().then(createWindow);ipc.on('invokeAction', (event, data) => {    var result = "test result!";    event.sender.send('actionReply', result);})在我希望用来操作 DOM 的文件中,我尝试获取元素 ID,然后添加一个事件侦听器,如下所示:const ipc = require('electron').ipcRenderer;const helper = require("./api");var authenticate_button = ipcRenderer.getElementById("authenticate-button");var authButton = document.getElementById("authenticate-button");authButton.addEventListener("click", () => {    ipc.once('actionReply', (event, response) => {        console.log("Hello world!");    })    ipc.send('invokeAction');});function onAuthenticateClick() {    helper.authenticateLogin(api_public, api_secret, access_public, access_secret);}最后,我的 HTML 仅包含一个我希望将事件侦听器附加到的按钮:<!DOCTYPE html><html><head>    <meta charset="UTF-8" />    <meta name="viewport" content="width=device-width, initial-scale=1.0" />    <title>Project Test</title>    <link rel="stylesheet" href="style.css" /></head><body>    <div class="main-container">        <button id="authenticate-button" type="submit" onclick="">Authenticate</button>        <p id="status-label">Not Authenticated</p>    </div>    <script src="script.js"></script></body></html>如果有人能帮助我指出如何让这个基本功能发挥作用的正确方向,那将非常有帮助!
查看完整描述

2 回答

?
交互式爱情

TA贡献1712条经验 获得超3个赞

require未定义,因为您没有在nodeIntegration窗口上启用。在您的窗口配置中将其设置为 true:


const window = new BrowserWindow({

  transparent: true,

  frame: false,

  resizable: false,

  center: true,

  width: 410,

  height: 550,

  webPreferences: {

    nodeIntegration: true

  }

})


查看完整回答
反对 回复 2022-10-08
?
肥皂起泡泡

TA贡献1829条经验 获得超6个赞

正如 AlekseyHoffman 所提到的,您无法ipcRenderer在前端 js 文件中访问的原因是因为您已nodeIntegration设置为 false。也就是说,现在默认设置为 false 是有原因的。它使您的应用程序的安全性大大降低。


让我建议一种替代方法:与其尝试ipcRenderer通过设置为 true 来直接从前端 js访问,不如nodeIntegration从 preload.js 访问它。在 preload.js 中,您可以有选择地公开您想要在前端访问的 ipcMain 函数(来自您的 main.js 文件)(包括那些可以从 main.js 发回数据的函数),并通过ipcRenderer那里调用它们。在您的前端 js 中,您可以访问公开这些功能的 preload.js 对象;preload.js 然后将调用这些 main.js 函数ipcRenderer,并将数据返回给调用它的前端 js。


这是一个简单但完全有效的示例(这些文件应该足以构建一个在 main.js 和前端之间具有双向通信的电子应用程序。在此示例中,以下所有文件都位于同一目录中。):


main.js


// boilerplate code for electron..

const {

    app,

    BrowserWindow,

    ipcMain,

    contextBridge

} = require("electron");

const path = require("path");  

let win;


/**

 * make the electron window, and make preload.js accessible to the js

 * running inside it (this will allow you to communicate with main.js

 * from the frontend).

 */

async function createWindow() {


    // Create the browser window.

    win = new BrowserWindow({

        width: 800,

        height: 600,

        webPreferences: {

            nodeIntegration: false, // is default value after Electron v5

            contextIsolation: true, // protect against prototype pollution

            enableRemoteModule: false,

            preload: path.join(__dirname, "./preload.js") // path to your preload.js file

        }

    });


    // Load app

    win.loadFile(path.join(__dirname, "index.html"));

}

app.on("ready", createWindow);


// end boilerplate code... now on to your stuff


/** 

 * FUNCTION YOU WANT ACCESS TO ON THE FRONTEND

 */

ipcMain.handle('myfunc', async (event, arg) => {

  return new Promise(function(resolve, reject) {

    // do stuff

    if (true) {

        resolve("this worked!");

    } else {

        reject("this didn't work!");

    }

  });  

});

请注意,我使用的示例是ipcMain.handle因为它允许双向通信并返回一个 Promise 对象 - 即,当您通过 preload.js 从前端访问此函数时,您可以使用其中的数据取回该 Promise。


preload.js:


// boilerplate code for electron...

const {

    contextBridge,

    ipcRenderer

} = require("electron");


// All of the Node.js APIs are available in the preload process.

// It has the same sandbox as a Chrome extension.

window.addEventListener('DOMContentLoaded', () => {

    const replaceText = (selector, text) => {

        const element = document.getElementById(selector)

        if (element) element.innerText = text

    }


    for (const type of ['chrome', 'node', 'electron']) {

        replaceText(`${type}-version`, process.versions[type])

    }

})


// end boilerplate code, on to your stuff..


/**

 * HERE YOU WILL EXPOSE YOUR 'myfunc' FROM main.js

 * TO THE FRONTEND.

 * (remember in main.js, you're putting preload.js

 * in the electron window? your frontend js will be able

 * to access this stuff as a result.

 */

contextBridge.exposeInMainWorld(

    "api", {

        invoke: (channel, data) => {

            let validChannels = ["myfunc"]; // list of ipcMain.handle channels you want access in frontend to

            if (validChannels.includes(channel)) {

                // ipcRenderer.invoke accesses ipcMain.handle channels like 'myfunc'

                // make sure to include this return statement or you won't get your Promise back

                return ipcRenderer.invoke(channel, data); 

            }

        },

    }

);

渲染器进程(即您的前端 js 文件 - 我将其称为 frontend.js):


// call your main.js function here

console.log("I'm going to call main.js's 'myfunc'");

window.api.invoke('myfunc', [1,2,3])

    .then(function(res) {

        console.log(res); // will print "This worked!" to the browser console

    })

    .catch(function(err) {

        console.error(err); // will print "This didn't work!" to the browser console.

    });

索引.html


<!DOCTYPE html>

<html>


<head>

    <title>My Electron App</title>

</head>


<body>

    <h1>Hello Beautiful World</h1>

    <script src="frontend.js"></script> <!-- load your frontend script -->

</body>

</html>

包.json


{

  "name": "myapp",

  "main": "main.js",

  "scripts": {

    "start": "electron ."

  }

}

上面的文件应该足以拥有一个在 main.js 和前端 js 之间进行通信的完整工作的电子应用程序。将它们全部放在一个名为main.js、preload.js、frontend.js和的目录中index.html,然后package.json使用npm start. 请注意,在此示例中,我将所有文件存储在同一目录中;确保将这些路径更改为它们存储在系统上的任何位置。


查看完整回答
反对 回复 2022-10-08
  • 2 回答
  • 0 关注
  • 227 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信