【问题标题】:What's the proper way to handle forms in Electron?在 Electron 中处理表单的正确方法是什么?
【发布时间】:2017-04-09 20:22:03
【问题描述】:

表单 html 和提交事件是“渲染器”的一部分。 提交的数据应该在主进程中可用。 提交表单并使该数据在 main.js 中可访问的正确方法是什么?

我应该简单地使用“远程”模块将数据从 main.js 传递给函数还是有更好的方法?

【问题讨论】:

  • 你是从前端框架的角度问,还是纯粹的电子?

标签: javascript node.js forms electron


【解决方案1】:

我们使用服务(Angular)来处理窗口中的表单数据。如果需要,然后通知remote


您可以从您的rendereripc 发送数据,然后在您的main.js 中捕获此事件和传递的表单数据:

// renderer.js
let ipcRenderer = require('electron').ipcRenderer;
ipcRenderer.send('submitForm', formData);

// main.js
ipcMain.on('submitForm', function(event, data) {
   // Access form data here
});

您还可以将消息从main.js 发送回renderer

同步

// main.js
ipcMain.on('submitForm', function(event, data) {
   // Access form data here
   event.returnValue = {"any": "value"};
});

异步

// main.js
ipcMain.on('submitForm', function(event, data) {
   // Access form data here
   event.sender.send('formSubmissionResults', results);
});

// renderer.js
ipcRenderer.on('formSubmissionResults', function(event, args) {
   let results = args.body;
});

【讨论】:

  • 即使是离线应用程序,这仍然是一种方法吗?
【解决方案2】:

如何做到这一点有多种变化,但都是通过IPC

IPC(进程间通信)是从渲染进程获取数据到主进程的唯一方法,并且是事件驱动的。这样做的方式是,您可以使用进程监听的自定义事件,并在该事件发生时返回一些内容。

@Adam Eri 所述的示例是文档中ipcMain example 的一种变体,但这种方法并非一刀切。

之所以这么说,是因为如果您尝试通过菜单(通常在主进程上运行)或通过 Vue 或 Angular 等前端框架通过组件发送事件,事情很快就会变得复杂。

我举几个例子:

通过WebContents使用远程

就您而言,是的,您可以使用电子remote,但出于表单的目的不推荐使用此方法。根据文档,远程的意义在于

使用渲染器进程中的主进程模块

tl:dr - 由于其同步性质,此过程可能导致死锁,可能导致事件对象泄漏(由于垃圾收集),并通过回调导致意外结果。

可以从文档中获得进一步的解释,但最终这是为在渲染过程中使用 dialogmenu 等项目而设置的。

index.js(主进程)

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

let window;

function createWindow(){
    window = new BrowserWindow({
        show: false
    });

    window.loadURL(`file://${__dirname}/index.html`);
    window.once('ready-to-show', function (){
        window.show();
    });

    window.webContents.openDevTools();

    let contents = window.webContents;

    window.on('closed', function() {
        window = null;
    });
}

exports.handleForm = function handleForm(targetWindow, firstname) {
    console.log("this is the firstname from the form ->", firstname)
    targetWindow.webContents.send('form-received', "we got it");
};

app.on('ready', function(){
    createWindow();
});

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Electron App</title>
    </head>

    <body>

        <form action="#" id="ipcForm2">
            First name:<br>
            <input type="text" name="firstname" id="firstname" value="John">
            <br>
            Last name:<br>
            <input type="text" name="lastname" id="lastname" value="Smith">
            <br><br>
            <input id="submit" type="submit" value="submit">
        </form>

        <p id="response"></p>

        <script src='renderFile.js'></script>
    </body>
</html>

renderFile.js(渲染过程)

const { remote, ipcRenderer } = require('electron');
const { handleForm} = remote.require('./index');
const currentWindow = remote.getCurrentWindow();

const submitFormButton = document.querySelector("#ipcForm2");
const responseParagraph = document.getElementById('response')

submitFormButton.addEventListener("submit", function(event){
        event.preventDefault();   // stop the form from submitting
        let firstname = document.getElementById("firstname").value;
        handleForm(currentWindow, firstname)
});

ipcRenderer.on('form-received', function(event, args){
    responseParagraph.innerHTML = args
    /*
        you could choose to submit the form here after the main process completes
        and use this as a processing step
    */
});

传统 IPC

index.js(主进程)

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

let window;

function createWindow(){
    window = new BrowserWindow({
        show: false
    });

    window.loadURL(`file://${__dirname}/index.html`);
    window.once('ready-to-show', function (){
        window.show();
    });

    window.webContents.openDevTools();

    let contents = window.webContents;

    window.on('closed', function() {
        window = null;
    });
}

ipcMain.on('form-submission', function (event, firstname) {
    console.log("this is the firstname from the form ->", firstname)
});

app.on('ready', function(){
    createWindow();
});

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Electron App</title>
    </head>

    <body>

        <form name="ipcForm" onSubmit="JavaScript:sendForm(event)">
            First name:<br>
            <input type="text" name="firstname" id="firstname" value="John">
            <br>
            Last name:<br>
            <input type="text" name="lastname" id="lastname" value="Smith">
            <br><br>
            <input type="submit" value="Submit">
        </form>

        <script src='renderFile.js'></script>
    </body>
</html>

renderFile.js(渲染过程)

const ipcRenderer = require('electron').ipcRenderer;

function sendForm(event) {
    event.preventDefault() // stop the form from submitting
    let firstname = document.getElementById("firstname").value;
    ipcRenderer.send('form-submission', firstname)
}

使用网页内容

第三个可能的选项是webContents.executeJavascript,用于从主进程访问渲染器进程。此解释来自remote 文档部分。

总结

如您所见,有一些关于如何使用 Electron 处理表单的选项。只要你用IPC就可以了;只是你如何使用它会给你带来麻烦。我已经展示了用于处理表单的普通 javascript 选项,但是有无数种方法可以做到这一点。当您将前端框架加入其中时,它会变得更加有趣。

我个人尽可能使用传统的 IPC 方法。

希望能为您解决问题!

【讨论】:

  • 我仍然不清楚为什么不推荐您使用传统的 IPC 方式。如果我不使用 Angular 之类的框架怎么办?
  • 如果您阅读了上面的摘要,您会更加清楚。我不推荐传统 IPC 之外的任何东西(您必须将此答案与我上面的 Adam 混淆)。我给你一个例子,如何在没有框架的情况下做到这一点
【解决方案3】:

远程是共享数据的好方法。使用全局变量并与我们电子应用程序的其他页面共享它们。因此,基于以下 IPC 方法,我能够以这种方式对其进行管理:

1) 在 main.js 文件中添加这段代码:

   global.MyGlobalObject = {
      variable_1: '12345'
   }

2) 在您的第一页上使用它来更新全局变量值:

require('electron').remote.getGlobal('MyGlobalObject').variable_1= '4567'

3) 最后,在第二页上使用类似这样的内容,您将在其中访问修改后的全局变量并打印它:

console.log(require('electron').remote.getGlobal('MyGlobalObject').variable_1)

你可以在electron的documentation找到同样的东西。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-29
    • 2021-10-30
    • 2020-12-02
    相关资源
    最近更新 更多