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的引用都是跟版本掛鉤了,大家如果一意孤行還要用使用不推薦的方式來使用原生能力的話,那么配置就按照上面的來做即可了。