应用程序现在可以触发“Open File”对话框并读取用户在主进程中选择的文件。我们还向进程中的Open File按钮添加了一个事件监听器。现在只需要使用我们前面讨论过的进程间通信技术将它们连接起来。
理解CommonJS引用系统通过remote模块使用主进程的功能,我们需要利用Node的CommonJS模块系统向应用程序中的其他文件公开该功能。在本书中,我们使用了require从Electron,Node标准库和第三方库中提取功能,但这是我们第一次将其与我们的代码一起使用。让我们花几分钟回顾一下它是如何工作的。
Node的模块系统由2个主要的方法所组成:从其他来源获取功能的能力,以及导出功能供其他来源使用的能力。当我们需要来自其他资源的代码时,其他资源可以是我们编写的文件、一个第三方模块、一个Node模块或Electron提供的模块。我们在主进程和渲染进程的顶部都使用了Node的内置requrie函数
当我们需要一个模块时,我们究竟要导入什么?在Node中,我们显式地声明应该从模块导出什么功能,如清单4.8所示。这个函数在清单4.9中导入,Node中的每个模块都有一个名为exports的内置对象,它从一个空对象开始。当我们从另一个文件中需要导出对象时,添加到导出对象的任何内容都是可用的。
清单4.8 在Node导出一个函数: basic-math.js
exports.addTwo = n => n + 2;清单4.9 在Node导入一个函数
const basicMath = require('./basic-math'); basicMath.addTwo(4); //返回6 从另一个进程引用功能内置的require函数不能跨进程工作。当我们在渲染器进程中工作时,我们使用内置的require函数导入的任何功能都将是渲染器进程的一部分。当我们在主进程中工作时,我们需要的任何功能都将是主进程的一部分。但是当我们在渲染器进程中想要从主进程中获得功能时,会发生什么呢?
Electron的remote模块有它自己的require方法,在我们的渲染器进程中允许它从主进程获取功能。使用remote.require返回代理对象—类似于远程对象上的其他属性。Electron代表我们负责所有的进程间通信。
要实现本章开头所述的功能,主进程必须导出它的getFileFromUser()函数,以便我们可以将它导入到渲染器进程代码中。这个清单更新了app/main.js中的一行。
清单4.10 从渲染器进程中导出打开文件对话框的功能: ./app/main.js
const getFileFromUser = exports.getFileFromUser = () => { //除了在这个文件中创建一个常量外,我们还将它指定为exports对象的一个属性,该属性可以从其他文件(特别是渲染器进程)访问。 const files = dialog.showOpenDialog(mainWindow, { properties: ['openFile'], filters: [ { name: 'Text Files', extensions: ['txt'] }, { name: 'Markdown Files', extensions: ['md', 'markdown'] } ] }); if (files) { returun; } const file = files[0]; const content = fs.readFileSync(file).toString(); console.log(content); };代码接受我们创建的getFileFromUser()函数,并将其导出为exports对象上具有相同名称的属性。渲染进程需要引入Electron的 remote 模块,然后使用remote.require。从渲染器进程的主进程获取对getFileFromUser()函数的引用。这与清单4.11中内置的require函数不同,因为导入的代码是根据主进程计算的,而不是根据引入它的渲染器进程计算的。这需要四个步骤:
在渲染器进程中需要Electron。
存储对remote的引用。
使用remote.require请求主进程。
存储从主进程导出的getFileFromUser()函数的应用。
列表4.11 渲染器进程中需要主进程的功能: ./app/renderer.js
const { remote } = require('electron'); const mainProcess = remote.require('./main.js');现在,我们可以在渲染器进程中调用从主进程导出getFileFromUser()函数。让我们替换事件监听器中的功能,以触发Open File对话框,而不是触发警报。
列表4.12 从UI触发主进程中的getFileFromUser(): ./app/ renderer.js
openFileButton.addEventListener('click', () => { mainProcess.getFileFromUser(); });如果我们启动Electron应用程序并单击“Open File”按钮,它将正确地触发“打开文件”对话框。有了这些,我们仍然只将文件记录到主进程中的控制台。为了完成我们的特性,主进程必须将文件的内容发送回呈现器进程,以便在我们的应用程序中显示。
将内容从主进程发送到渲染器进程remote模块促进了渲染器进程访问主进程的能力,但是它不允许主进程访问渲染器进程。要将用户选择的文件内容发送回要在UI中呈现的渲染器进程的话,我们需要学习进程之间通信的另一种技术。