开发者问题收集

electron v10.1.1 给出 Uncaught TypeError: 无法读取未定义的属性“dialog”,但相同的代码在 electron v9.3.0 中可以工作

2020-09-05
11425

我试图在 electron 应用程序中上传文件,该应用程序在 electron v9.3.0 中运行良好,但当我使用 electron v10.1.1 时,它会出现以下错误 Uncaught TypeError: Cannot read property 'dialog' of undefined 在此行 const dialog = electron.remote.dialog; 参见下面的屏幕截图。 在此处输入图片描述

main.js内容如下

const { app, BrowserWindow } = require('electron') 

function createWindow () { 
// Create the browser window. 
const win = new BrowserWindow({ 
    width: 800, 
    height: 600, 
    webPreferences: { 
    nodeIntegration: true
    } 
}) 

// Load the index.html of the app. 
win.loadFile('src/index.html') 

// Open the DevTools. 
win.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. 
// This method is equivalent to 'app.on('ready', function())' 
app.whenReady().then(createWindow) 

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

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() 
} 
}) 

// 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.js内容如下

const electron = require('electron'); 
const path = require('path'); 

// Importing dialog module using remote 
const dialog = electron.remote.dialog;

var uploadFile = document.getElementById('upload'); 

// Defining a Global file path Variable to store 
// user-selected file 
global.filepath = undefined; 

uploadFile.addEventListener('click', () => { 
// If the platform is 'win32' or 'Linux' 
    if (process.platform !== 'darwin') { 
        // Resolves to a Promise<Object> 
        dialog.showOpenDialog({ 
            title: 'Select the File to be uploaded', 
            defaultPath: path.join(__dirname, '../assets/'), 
            buttonLabel: 'Upload', 
            // Restricting the user to only Text Files. 
            filters: [ 
                { 
                    name: 'Text Files', 
                    extensions: ['txt', 'docx'] 
                }, ], 
            // Specifying the File Selector Property 
            properties: ['openFile'] 
        }).then(file => { 
            // Stating whether dialog operation was 
            // cancelled or not. 
            console.log(file.canceled); 
            if (!file.canceled) { 
            // Updating the GLOBAL filepath variable 
            // to user-selected file. 
            global.filepath = file.filePaths[0].toString(); 
            console.log(global.filepath); 
            } 
        }).catch(err => { 
            console.log(err) 
        }); 
    } 
    else { 
        // If the platform is 'darwin' (macOS) 
        dialog.showOpenDialog({ 
            title: 'Select the File to be uploaded', 
            defaultPath: path.join(__dirname, '../assets/'), 
            buttonLabel: 'Upload', 
            filters: [ 
                { 
                    name: 'Text Files', 
                    extensions: ['txt', 'docx'] 
                }, ], 
            // Specifying the File Selector and Directory 
            // Selector Property In macOS 
            properties: ['openFile', 'openDirectory'] 
        }).then(file => { 
            console.log(file.canceled); 
            if (!file.canceled) { 
            global.filepath = file.filePaths[0].toString(); 
            console.log(global.filepath); 
            } 
        }).catch(err => { 
            console.log(err) 
        }); 
    } 
}); 

index.html内容如下

<!DOCTYPE html> 
<html> 
<head> 
    <meta charset="UTF-8"> 
    <title>Hello World!</title> 
    <!-- https://electronjs.org/docs/tutorial 
                        /security#csp-meta-tag -->
    <meta http-equiv="Content-Security-Policy"
        content="script-src 'self' 'unsafe-inline';" /> 
</head> 
<body> 
    <h1>Hello World!</h1> We are using node 
    <script> 
        document.write(process.versions.node) 
    </script>, Chrome 
    <script> 
        document.write(process.versions.chrome) 
    </script>, and Electron 
    <script> 
        document.write(process.versions.electron) 
    </script>. 

    <h3>File Upload in Electron</h3> 
    <button id="upload">Upload File</button> 
    
    <!-- Adding Individual Renderer Process JS File -->
    <script src="index.js"></script> 
</body> 
</html> 
3个回答
const win = new BrowserWindow({ 
    width: 800, 
    height: 600, 
    webPreferences: { 
         enableRemoteModule: true,
         nodeIntegration: true
    } 
}) 

为了访问渲染器进程上的 remote 模块。我们需要启用 enableRemoteModuletrue ,因为从较新版本开始,这是默认的 false

tpikachu
2020-09-05

正如 @tpikatchu 所述:

const win = new BrowserWindow({ 
    width: 800, 
    height: 600, 
    webPreferences: { 
         enableremotemodule: true,
         nodeIntegration: true
    } 
})

enableremotemodule: true
必须采用驼峰式命名法: enableRemoteModule: true

参考: https://www.electronjs.org/docs/api/browser-window

附言:抱歉,我刚刚创建了新答案,但我还无法发表评论。

Melas
2020-09-05

对于 Electron 11.0 及以上版本

远程模块已被弃用。这意味着更新文件所需的对话框对象无法从渲染器 javascript 文件(例如本文中的 index.js )访问。对话框对象仍可从主入口点访问。为了解决这个问题,您可以使用 ipcMainipcRenderer 对象来管理入口点和渲染器 javascript 代码之间的通信。

main.js (或您应用中使用的入口点)中添加以下内容:

const {app, BrowserWindow, dialog, ipcMain } = require('electron')

// *** REST OF YOUR CODE GOES HERE *** 

ipcMain.on('file-request', (event) => {  
  // If the platform is 'win32' or 'Linux'
  if (process.platform !== 'darwin') {
    // Resolves to a Promise<Object>
    dialog.showOpenDialog({
      title: 'Select the File to be uploaded',
      defaultPath: path.join(__dirname, '../assets/'),
      buttonLabel: 'Upload',
      // Restricting the user to only Text Files.
      filters: [ 
      { 
         name: 'Text Files', 
         extensions: ['txt', 'docx'] 
      }, ],
      // Specifying the File Selector Property
      properties: ['openFile']
    }).then(file => {
      // Stating whether dialog operation was
      // cancelled or not.
      console.log(file.canceled);
      if (!file.canceled) {
        const filepath = file.filePaths[0].toString();
        console.log(filepath);
        event.reply('file', filepath);
      }  
    }).catch(err => {
      console.log(err)
    });
  }
  else {
    // If the platform is 'darwin' (macOS)
    dialog.showOpenDialog({
      title: 'Select the File to be uploaded',
      defaultPath: path.join(__dirname, '../assets/'),
      buttonLabel: 'Upload',
      filters: [ 
      { 
         name: 'Text Files', 
         extensions: ['txt', 'docx'] 
      }, ],
      // Specifying the File Selector and Directory 
      // Selector Property In macOS
      properties: ['openFile', 'openDirectory']
    }).then(file => {
      console.log(file.canceled);
      if (!file.canceled) {
      const filepath = file.filePaths[0].toString();
      console.log(filepath);
      event.send('file', filepath);
    }  
  }).catch(err => {
      console.log(err)
    });
  }
});

index.js 中的代码替换为:

const { ipcRenderer } = require('electron');
var uploadFile = document.getElementById('upload');

//upon clicking upload file, request the file from the main process
uploadFile.addEventListener('click', () => {
  ipcRenderer.send('file-request');
});

//upon receiving a file, process accordingly
ipcRenderer.on('file', (event, file) => {
  console.log('obtained file from main process: ' + file);
});

注意: 我正在使用异步事件。可以通过使用 ipcRenderer.sendSync 并处理返回值来实现同步 - 请查看 electron 文档 了解更多信息。两者的区别在于 sendSync 是一个同步承诺:它会阻塞窗口,直到 ipcMain 发出返回值。对于这样的过程,这似乎是可取的,因为我们可能希望窗口等待文件上传,直到允许用户继续交互。我没有那样做,因为:

  • 如果处理不当,它会阻止整个应用程序,如 在 electron 文档中
  • 即使应用程序在 sendSync 上被阻止,按钮点击也会被处理。一旦文件对话框关闭,应用程序将触发已进行的所有点击响应,因此阻止并不那么有用。
  • 可以使用简单的布尔值并管理 cancel 选项来管理渲染器 javascript 上对话框是否打开 - 如果有人需要,我们很乐意提供此功能!
Diana Vallverdu
2022-04-24