document.getElementById("myFile").value 使用 electron 未定义

document.getElementById("myFile").value gets undefined using electron

我有一个非常基本的 html 文件(使用电子);

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title> File Uploader </title>
    <link rel="stylesheet" href="style.css">
    <script defer src="render.js"></script>
</head>
<body>
    
    <h1>Drive File Uploader</h1>
    <input type="file" id="myFile" name="myFile">
    <button onclick="FileUploadPing()">Upload your file</button>

</body>
</html>

和一个名为 render.js;

的事件侦听器
const ipcRenderer = require("electron").ipcRenderer;

const FileUploadPing = () => {
  var input = document.getElementById("myFile").value
  if (input) {
    ipcRenderer.send("FileUploadPing",inputVal);
  }else{console.log("no path value")}
};

ipcRenderer.on("FileRecievePing", (event, data) => {
  alert(data)
});

但是当我点击提交时,document.getElementById("myFile").value returns undefined

如何提取该值?

这是一个有趣的问题,许多使用 Electron 的人都会遇到这个问题。可以使用(通过 Electron)原生的 OS dialog.showOpenDialog([browserWindow, ]options) dialog or the html <input type="file"> 标签。

为了避免管理 is prefixed with C:\fakepath\ 问题的需要,通常最好使用本机方法。毕竟,那是 Electron 最擅长的。

让我向您展示如何快速设置一个 html 按钮,单击该按钮将打开本机文件选择器对话框,并且在选择路径时,return 渲染路径用于显示的线程。

在下面的代码中,我们将使用配置为通信的 preload.js 脚本(using IPC) between the main thread and render thread(s). Context Isolation 将对此进行更详细的描述。

首先,让我们编写 main.js 文件,其中将包含本机文件对话框的创建。

main.js(主线程)

const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronDialog = require('electron').dialog;
const electronIpcMain = require('electron').ipcMain;

const nodePath = require("path");

// Prevent garbage collection
let window;

function createWindow() {
    const window = new electronBrowserWindow({
        x: 0,
        y: 0,
        width: 1000,
        height: 700,
        show: false,
        webPreferences: {
            nodeIntegration: false,
            contextIsolation: true,
            preload: nodePath.join(__dirname, 'preload.js')
        }
    });

    window.loadFile('index.html')
        .then(() => { window.show(); })

    return window;
}

electronApp.on('ready', () => {
    window = createWindow();
});

electronApp.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        electronApp.quit();
    }
});

electronApp.on('activate', () => {
    if (electronBrowserWindow.getAllWindows().length === 0) {
        createWindow();
    }
});

// Open the file dialog
electronIpcMain.on('message:openDialog', (event) => {
    let options = {
        title: 'Select File',
        properties: ['openFile']
    };

    electronDialog.showOpenDialog(window, options)
        .then((result) => {
            if (result.canceled) {
                console.log('User cancelled file dialog.');
                return;
            }

            event.reply('message:dialogPath', result.filePaths[0]);
        })
        .catch((error) => { console.error(error); });
})

现在,让我们创建 index.html 文件,为了简单起见,它还在 <script> 标签中包含 Javascript。

NB: Instead of deferring your script in the <head>, you can include it just before the closing <html> tag. Placing it here effectively performs the same thing as defer in the <head> <script> tag.

index.html(渲染线程)

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Drive File Uploader</title>
    </head>

    <body>
        <div>Drive File Uploader</div>
        <hr>

        <label for="path">Path: </label>
        <input type="text" id="path" name="path">
        <input type="button" id="open-dialog" name="open-dialog" value="...">

        <input type="button" id="upload" value="Upload">
    </body>

    <script>
        // Let's declare it as it is used more than once
        let filePath = document.getElementById('path');

        // Event listeners
        document.getElementById('open-dialog').addEventListener('click', () => { window.ipcRender.send('message:openDialog'); });
        document.getElementById('upload').addEventListener('click', () => { console.log(filePath.value); });

        // IPC message from the main thread
        window.ipcRender.receive('message:dialogPath', (path) => { filePath.value = path; })
    </script>
</html>

最后,让我们添加 preload.js 脚本以允许主线程和渲染线程安全地相互通信。

Note: This is where we define our whitelisted channel names.

preload.js(主线程)

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

// White-listed channels.
const ipc = {
    'render': {
        // From render to main.
        'send': [
            'message:openDialog'
        ],
        // From main to render.
        'receive': [
            'message:dialogPath'
        ],
        // From render to main and back again.
        'sendReceive': []
    }
};

// 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);
            }
        }
    }
);

希望以上概述了使用(通过 Electron)本机对话框是多么简单。好处是它们具有 OS 特定的功能和感觉。

我不知道我做了什么不同,但是当我尝试这个时它突然起作用了。

main.js;

const { app, BrowserWindow, ipcMain } = require("electron");

let win = null;

const createWindow = () => {
  win = new BrowserWindow({
    width: 800,
    height: 600,
    resizable: true,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false,
      enableRemoteModule: true,
      nativeWindowOpen: true,
    },
  });

  win.loadFile("index.html");
};

app.whenReady().then(createWindow);

render.js;

const ipcRenderer = require("electron").ipcRenderer;
const {uploadFileToCloud} = require("C:/Users/efeba/desktop/pythonAndJS/ITGSProject/app.js")

const FileUploadPing = () => {
  var name = document.getElementById("myFile").value
  name = name.replace("C:\fakepath\","")
  console.log(name)
  var path = document.getElementById("myFile").files[0].path
  path = path.replace(name,"")
  path = path.replaceAll("\", "/") // beautify the string
  console.log(path)
  if (path) {
    uploadFileToCloud(name, path)
    alert("File Uploaded")
  }else{console.log("no path value")}
};

//file uploads but content is empty
//I suspect pulling the libraries in renderer has some problems, will
//try to make it by sending a ping to main.js

index.html;

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title> File Uploader </title>
    <link rel="stylesheet" href="style.css">
    <script defer src="render.js"></script>
</head>
<body>
    
    <h1>Drive File Uploader</h1>
    <input type="file" id="myFile" name="myFile">
    <button onclick="FileUploadPing()">Upload your file</button>

</body>
</html>

希望能帮到你