【问题标题】:("Document not defined" in renderer.js) - Sending data and rendering it in electron(renderer.js 中的“文档未定义”) - 发送数据并在电子中呈现
【发布时间】:2022-06-17 19:58:48
【问题描述】:

我正在尝试为身体定位数据创建一个调试应用程序。此数据通过我的receiveAndConversion.js 中的 MQTT 作为 JSON 接收。我能够正确接收数据并打印到控制台。到目前为止,一切都很好。但现在我希望在我的主窗口中显示我收到的值(例如当手合上时使屏幕变为绿色)。

我尝试了很多东西,包括 ipc 和添加 nodeIntegration: true, contextIsolation: false, enableRemoteModule: true, 作为main.js 中的首选项

研究这个有点痛苦,因为我总是遇到有人试图从main.js而不是渲染器更改DOM的问题。 我是电子新手,并且一直在文档上花费数小时,但他们的所有示例都是在启动应用程序时触发或通过按钮(用户交互)触发的。我需要在收到新消息时更改 DOM,这与用户交互或其他事情无关。

我现在的结构是这样的:

  • main.js
  • receiveAndConversion.js
  • index.html
  • renderer.js

除了receiveAndConversion.jsrenderer.jsmain.js中提到的Preferences之外,代码与The quick start guide大致相同。

似乎阻止我的主要问题是,我似乎无法从我收到新消息时运行的 receiveAndConversion.js mqttClient.on() 调用我的 renderer.js。我的想法是我可以从那里调用 render.js 中的渲染函数,但是从 receiveAndConversion.js 调用它时,我收到“未定义文档”错误(至少我相信这是原因)。

如果您对我如何实现这一点而无需将所有内容都放入 main.js 有一个想法,我将不胜感激。

您可以在下面找到完整的代码。

// main.js

// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain } = require('electron')
//const Renderer = require('electron/renderer')

const path = require('path')
const mqttClient = require('./receiveAndConversion.js')

const createWindow = () => {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      //nativeWindowOpen: true,
      nodeIntegration: true,
      contextIsolation: false,
      enableRemoteModule: true,
      preload: path.join(__dirname, 'preload.js')
    }
  })

  // and load the index.html of the app.
  mainWindow.loadFile('index.html')

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

}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
  //
  //ipcMain.handle('left-hand-closed', (event, arg) => {
  //  console.log('left hand is closed');
  //}
  //)
  createWindow()

  app.on('activate', () => {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit()
})

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<!--index.html-->

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
    <meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
    <title>Hello World!</title>
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using Node.js <span id="node-version"></span>,
    Chromium <span id="chrome-version"></span>,
    and Electron <span id="electron-version"></span>.

    <!-- Create different field which will be used to visualise if hands are open or not. So one field for left hand one field for right hand. -->
    <div id="left-hand"></div>
    <div id="right-hand"></div>


    <!-- You can also require other files to run in this process -->
    <script src="./renderer.js"></script>
  </body>
</html>
//renderer.js

// get info of open or closed hands from receiveAndConversion.js
// then make the left-hand div or right-hand div green or red depending on open or closed
//const {ipcRenderer} = require('electron')

// //write something in the divs
// leftHandDiv.innerHTML = 'Left Hand: ' + leftHandClosed
// rightHandDiv.innerHTML = 'Right Hand: ' + rightHandClosed


// ipcRenderer.handle('left-hand-closed', (event, arg) => {
//     leftHandDiv.innerHTML = 'Left Hand: ' + arg
// }
// )
// ipcRenderer.handle('right-hand-closed', (event, arg) => {
//     rightHandDiv.innerHTML = 'Right Hand: ' + arg
// }
// )

function handChange(leftHandClosed, rightHandClosed) {
//get the divs from the html file
const leftHandDiv = document.getElementById('left-hand')
const rightHandDiv = document.getElementById('right-hand')  

    //check if the hand is open or closed
if (leftHandClosed) {
    leftHandDiv.style.backgroundColor = 'green'
    console.log('left hand is closed');
} else {
    leftHandDiv.style.backgroundColor = 'red'
    console.log('left hand is open');

}

if (rightHandClosed) {
    rightHandDiv.style.backgroundColor = 'green'
    console.log('right hand is closed');

} else {
    rightHandDiv.style.backgroundColor = 'red'
    console.log('right hand is open');
}
}

//make handChange() usable outside of the renderer.js
module.exports = {
    handChange
}
// preload.js

// 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 dependency of ['chrome', 'node', 'electron']) {
      replaceText(`${dependency}-version`, process.versions[dependency])
    }
  })

【问题讨论】:

    标签: javascript html electron ipc


    【解决方案1】:

    要将receiveAndConversion.js 文件与main.js 文件分开并通过IPCindex.html 发送信号,您需要访问index.html 的Electrons 窗口实例。这可以通过使用“getter”方法来实现。因此需要将mainWindow 的创建(和获取)分离到它自己的文件中。

    preload.js 脚​​本的良好使用要求设置 nodeIntegration: falsecontextIsolation: true。此外,应该不需要使用任何形式的远程模块。我已经重新设计了您的 preload.js 脚本,仅用作主进程和渲染进程之间的一种通信形式。可以使用各种形式的preload.js 脚本,但在这种情况下,我使用了最简化(但不是很灵活)的方法。

    最后,由于无法访问您的 receiveAndConversion.js 文件,我模拟了一个随机手/位置数据流。

    如您所见,将域分离到各自的文件中可以使整个应用程序保持逻辑性、易于维护并且在添加其他功能时没有错误。


    main.js(主进程)

    // Require the necessary Electron modules
    const electronApp = require('electron').app;
    const electronBrowserWindow = require('electron').BrowserWindow;
    
    // Require the necessary Node modules
    const nodePath = require('path');
    
    // Require the necessary Application modules
    const appMainWindow = require(nodePath.join(__dirname, './main-window'));
    const appReceiveAndConversion = require(nodePath.join(__dirname, './receiveAndConversion'));
    
    // Prevent garbage collection
    let mainWindow;
    
    electronApp.on('ready', () => {
        mainWindow = appMainWindow.create();
        appReceiveAndConversion.run();
    });
    
    electronApp.on('window-all-closed', () => {
        if (process.platform !== 'darwin') {
            electronApp.quit();
        }
    });
    
    electronApp.on('activate', () => {
        if (electronBrowserWindow.getAllWindows().length === 0) {
            appMainWindow.create();
        }
    });
    

    在其自己的文件中拥有mainWindowcreate()get 方法允许包含在需要引用mainWindow 的任何其他文件中。

    main-window.js(主进程)

    // Require the necessary Electron modules
    const electronBrowserWindow = require('electron').BrowserWindow;
    
    // Require the necessary Node modules
    const nodePath = require('path');
    
    let mainWindow;
    
    function create() {
        mainWindow = new electronBrowserWindow({
            x: 0,
            y: 0,
            width: 800,
            height: 600,
            show: false,
            webPreferences: {
                nodeIntegration: false,
                contextIsolation: true,
                preload: nodePath.join(__dirname, './preload.js')
            }
        });
    
        mainWindow.loadFile('index.html')
            .then(() => { mainWindow.show(); })
    
        return mainWindow;
    }
    
    function get() {
        return mainWindow;
    }
    
    module.exports = {create, get}
    

    receiveAndConversion.js(主进程)

    嘲讽...

    // Require the necessary Node modules
    const nodePath = require('path');
    
    // Require the necessary Application modules
    const appMainWindow = require(nodePath.join(__dirname, './main-window'));
    
    let mainWindow;
    
    // Generate a random number
    function randomNumber(lower, upper) {
        return Math.floor(Math.random() * (upper - lower + 1) + lower)
    }
    
    // An infinitely polled function
    function listener() {
        let hand = (randomNumber(0, 1)) ? 'leftHand' : 'rightHand';
        let position = (randomNumber(0, 1)) ? 'opened' : 'closed';
    
        console.log(hand + ' ' + position); // Testing
    
        mainWindow.webContents.send(hand, position);
    }
    
    // Called from main.js
    function run() {
        mainWindow = appMainWindow.get();
        setInterval(() => { listener(); }, 350);
    }
    
    module.exports = {run}
    

    preload.js(主进程)

    一个简单(但严格)的例子。

    // Import the necessary Electron components
    const contextBridge = require('electron').contextBridge;
    const ipcRenderer = require('electron').ipcRenderer;
    
    // Exposed protected methods in the render process
    contextBridge.exposeInMainWorld(
        // Allowed 'ipcRenderer' methods
        'electronAPI', {
            // From main to render
            leftHand: (position) => {
                ipcRenderer.on('leftHand', position);
            },
            rightHand: (position) => {
                ipcRenderer.on('rightHand', position);
            }
        });
    

    与其通过 JavaScript 更改背景颜色,不如更改类名,或者再次更改此实例中的数据属性值。

    为简单起见,我在&lt;script&gt; 标签之间加入了修改后的renderer.js

    index.html.js(渲染进程)

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Electron Test</title>
            <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';"/>
            <style>
                body {
                    margin: 0;
                    padding: 0;
                    height: 100vh;
                    display: flex;
                    flex-flow: row nowrap;
                }
    
                #left-hand,
                #right-hand {
                    flex: 1 0 50%;
                    display: flex;
                    justify-content: center;
                    align-items: center;
                    font-size: 3em;
                }
    
                #left-hand[data-position="closed"],
                #right-hand[data-position="closed"] {
                    background-color: darkred;
                }
    
                #left-hand[data-position="opened"],
                #right-hand[data-position="opened"] {
                    background-color: darkgreen;
                }
            </style>
        </head>
    
        <body>
            <div id="left-hand" data-position="closed">Left Hand</div>
            <div id="right-hand" data-position="closed">Right Hand</div>
        </body>
    
        <script>
            let leftHand = document.getElementById('left-hand');
            let rightHand = document.getElementById('right-hand');
    
            window.electronAPI.leftHand((event, position) => {
                console.log('leftHand ' + position); // Testing
                leftHand.dataset.position = position;
            });
    
            window.electronAPI.rightHand((event, position) => {
                console.log('rightHand ' + position); // Testing
                rightHand.dataset.position = position;
            });
        </script>
    </html>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-17
      • 1970-01-01
      • 2018-09-17
      • 2020-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多