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

我正在学习使用 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>

如果有人能帮助我指出如何让这个基本功能发挥作用的正确方向,那将非常有帮助!


拉莫斯之舞
浏览 228回答 2
2回答

交互式爱情

require未定义,因为您没有在nodeIntegration窗口上启用。在您的窗口配置中将其设置为 true:const window = new BrowserWindow({&nbsp; transparent: true,&nbsp; frame: false,&nbsp; resizable: false,&nbsp; center: true,&nbsp; width: 410,&nbsp; height: 550,&nbsp; webPreferences: {&nbsp; &nbsp; nodeIntegration: true&nbsp; }})

肥皂起泡泡

正如 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 {&nbsp; &nbsp; app,&nbsp; &nbsp; BrowserWindow,&nbsp; &nbsp; ipcMain,&nbsp; &nbsp; contextBridge} = require("electron");const path = require("path");&nbsp;&nbsp;let win;/**&nbsp;* make the electron window, and make preload.js accessible to the js&nbsp;* running inside it (this will allow you to communicate with main.js&nbsp;* from the frontend).&nbsp;*/async function createWindow() {&nbsp; &nbsp; // Create the browser window.&nbsp; &nbsp; win = new BrowserWindow({&nbsp; &nbsp; &nbsp; &nbsp; width: 800,&nbsp; &nbsp; &nbsp; &nbsp; height: 600,&nbsp; &nbsp; &nbsp; &nbsp; webPreferences: {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nodeIntegration: false, // is default value after Electron v5&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; contextIsolation: true, // protect against prototype pollution&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; enableRemoteModule: false,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; preload: path.join(__dirname, "./preload.js") // path to your preload.js file&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; });&nbsp; &nbsp; // Load app&nbsp; &nbsp; win.loadFile(path.join(__dirname, "index.html"));}app.on("ready", createWindow);// end boilerplate code... now on to your stuff/**&nbsp;&nbsp;* FUNCTION YOU WANT ACCESS TO ON THE FRONTEND&nbsp;*/ipcMain.handle('myfunc', async (event, arg) => {&nbsp; return new Promise(function(resolve, reject) {&nbsp; &nbsp; // do stuff&nbsp; &nbsp; if (true) {&nbsp; &nbsp; &nbsp; &nbsp; resolve("this worked!");&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; reject("this didn't work!");&nbsp; &nbsp; }&nbsp; });&nbsp;&nbsp;});请注意,我使用的示例是ipcMain.handle因为它允许双向通信并返回一个 Promise 对象 - 即,当您通过 preload.js 从前端访问此函数时,您可以使用其中的数据取回该 Promise。preload.js:// boilerplate code for electron...const {&nbsp; &nbsp; contextBridge,&nbsp; &nbsp; 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', () => {&nbsp; &nbsp; const replaceText = (selector, text) => {&nbsp; &nbsp; &nbsp; &nbsp; const element = document.getElementById(selector)&nbsp; &nbsp; &nbsp; &nbsp; if (element) element.innerText = text&nbsp; &nbsp; }&nbsp; &nbsp; for (const type of ['chrome', 'node', 'electron']) {&nbsp; &nbsp; &nbsp; &nbsp; replaceText(`${type}-version`, process.versions[type])&nbsp; &nbsp; }})// end boilerplate code, on to your stuff../**&nbsp;* HERE YOU WILL EXPOSE YOUR 'myfunc' FROM main.js&nbsp;* TO THE FRONTEND.&nbsp;* (remember in main.js, you're putting preload.js&nbsp;* in the electron window? your frontend js will be able&nbsp;* to access this stuff as a result.&nbsp;*/contextBridge.exposeInMainWorld(&nbsp; &nbsp; "api", {&nbsp; &nbsp; &nbsp; &nbsp; invoke: (channel, data) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let validChannels = ["myfunc"]; // list of ipcMain.handle channels you want access in frontend to&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (validChannels.includes(channel)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // ipcRenderer.invoke accesses ipcMain.handle channels like 'myfunc'&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // make sure to include this return statement or you won't get your Promise back&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return ipcRenderer.invoke(channel, data);&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; },&nbsp; &nbsp; });渲染器进程(即您的前端 js 文件 - 我将其称为 frontend.js):// call your main.js function hereconsole.log("I'm going to call main.js's 'myfunc'");window.api.invoke('myfunc', [1,2,3])&nbsp; &nbsp; .then(function(res) {&nbsp; &nbsp; &nbsp; &nbsp; console.log(res); // will print "This worked!" to the browser console&nbsp; &nbsp; })&nbsp; &nbsp; .catch(function(err) {&nbsp; &nbsp; &nbsp; &nbsp; console.error(err); // will print "This didn't work!" to the browser console.&nbsp; &nbsp; });索引.html<!DOCTYPE html><html><head>&nbsp; &nbsp; <title>My Electron App</title></head><body>&nbsp; &nbsp; <h1>Hello Beautiful World</h1>&nbsp; &nbsp; <script src="frontend.js"></script> <!-- load your frontend script --></body></html>包.json{&nbsp; "name": "myapp",&nbsp; "main": "main.js",&nbsp; "scripts": {&nbsp; &nbsp; "start": "electron ."&nbsp; }}上面的文件应该足以拥有一个在 main.js 和前端 js 之间进行通信的完整工作的电子应用程序。将它们全部放在一个名为main.js、preload.js、frontend.js和的目录中index.html,然后package.json使用npm start. 请注意,在此示例中,我将所有文件存储在同一目录中;确保将这些路径更改为它们存储在系统上的任何位置。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python