1 进程
Electron里头的进程分为渲染进程和主进程。简单理解:
- main.js就是主进程
- 每个页面就是渲染进程
- 一个Electron应用仅有一个主进程,可以有多个渲染进程
上面的这些概念很重要,不展开细讲。
2 进程职责
主进程是用来实现应用的基础功能,包括跟底层的系统交互等。渲染进程是用来实现具体每个页面的功能。
那么当渲染进程需要跟系统底层进行交互的时候,怎么处理呢?目前有两种方式:
- 在渲染进程里头直接引用支持跟底层进行交互的包,然后直接实现跟底层的交互(十分不推荐)
- 渲染进程将事件委托给主进程,让主进程来完成。(推荐)
- 事件委托是通过事件监听和触发来实现的。
3 渲染进程与Native API
虽然上面说了,不建议渲染进程直接调用Native API,但是还是要说下,渲染进程如何实现直接调用底层API。
之所以不建议渲染进程直接调用Native API是因为,渲染进程调用原生能力,其实是从主进程同步过来的,那么在应用的使用过程,就要不断的实现主进程和渲染进程之间的原生能力载体的状态同步,这个同步是十分耗费宿主机资源的。
3.1保存文件
下面的案例是讲解下如何通过渲染进程直接调用原生API。
3.1.1 渲染进程页面
先用h5画出包含有一个文本框和用来保存的按钮。
源码如下:
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>electron从入门到精通</title>
</head>
<body> <button type="button" id="saveBtn">保存文件</button><textarea id="textArea" style="position:absolute;top:60px;bottom:0;left:0;right:0;"></textarea>
<script src="./test.js"></script>
</body>
</html>
然后test.js的源码如下:
const { dialog } = require('@electron/remote')
//引入fs模块
var fs = require('fs')
//获取文本框的dom
var textAreaDom = document.querySelector('#textArea')
var saveBtn = document.getElementById('saveBtn')// 文件保存路径,第一保存后,就缓存起来
var currentPath = null
saveBtn.addEventListener('click',function(){if (currentPath) {writeFile(currentPath)} else {// 调用native api实现文件保存dialog.showSaveDialog({properties:['showOverwriteConfirmation']}).then(({canceled,filePath})=>{if (!canceled) {writeFile(filePath)currentPath = filePath}})}})
function writeFile(path,){fs.writeFileSync(path, textAreaDom.value)}
到这边要停下来下,缓一缓捋一捋。
首先,我们需要在渲染进程里头引用node的包,fs包,其次,还用到了remote的依赖包。因此还需要做如下操作:
- 安装@electron/remote,版本:2.0.12
npm install @electron/remote@2.0.12
- 调整渲染进程窗口的创建配置。创建窗口是在main.js里实现的,下面直接附上整个main.js的文件:
// main.jsconst { app, BrowserWindow} = require('electron')const path = require('path')// *************************1.引入remote模块******************************const remote = require("@electron/remote/main");remote.initialize();function createWindow () {const mainWindow = new BrowserWindow({width: 800,height: 600,webPreferences:{// 渲染进程 开启node模块,使得JS中可以使用node的modelnodeIntegration:true,// 开启 remote 模块enableBlinkFeatures:true,// 控制上下文隔离contextIsolation:false,//由于安全问题,remote模块默认关闭enableRemoteModule: true,//开启remote模块//关闭web权限检查,允许跨域webSecurity: false,}})mainWindow.loadFile('./src/index.html')// 默认打开调试工具mainWindow.webContents.openDevTools()// ********2.启用remote模块,渲染进程就可以使用主程序模块********************remote.enable(mainWindow.webContents); }app.whenReady().then(() => {createWindow()app.on('activate', () => {if (BrowserWindow.getAllWindows().length === 0) {createWindow()}})})app.on('window-all-closed', () => {if (process.platform !== 'darwin') {app.quit()}})
至此,源码分享就结束了。
4 源码解释
4.1 test.js和Electron的原生能力
上面主要麻烦的就是test.js里头的dialog的使用。这个调用的是原生能力的弹窗,其实像原生能力的使用,不知道都觉得很麻烦,但是,如果知道了,就不难,下面附上原生能力的工具字典:
app | Electron
4.2 remote模块
不同版本的Electron使用的remote是不一样的,main.js里头关于remote的配置,以及渲染进程里头的remote的引用都是跟版本挂钩了,大家如果一意孤行还要用使用不推荐的方式来使用原生能力的话,那么配置就按照上面的来做即可了。