Electron 是一個可使用 Web 技術如 JavaScript、HTML 和 CSS 來建立跨平臺原生桌面應用的框架。藉助 Electron,咱們可使用純 JavaScript 來調用豐富的原生 APIs。javascript
Electron用 web 頁面做爲它的 GUI,而不是綁定了 GUI 庫的 JavaScript。它結合了 Chromium、Node.js 和用於調用操做系統本地功能的 APIs(如打開文件窗口、通知、圖標等)。html
如今已經有不少由 Electron 開發應用,好比 Atom、Insomnia、Visual Studio Code 等。查看更多使用 Electron 構建的項目能夠訪問 [Apps Built on Electron
](https://electron.atom.io/apps/)前端
安裝 electron 以前,須要安裝 Node.js。若是沒有安裝,推薦使用 nvm 等 Node.js 版本管理工具進行安裝/java
而後建議修改 electron 的源爲國內源:node
$ export ELECTRON_MIRROR="https://npm.taobao.org/mirrors/electron/"
否則會出現以下錯誤:git
Error: connect ETIMEDOUT 54.231.50.42:443 at Object.exports._errnoException (util.js:1016:11) at exports._exceptionWithHostPort (util.js:1039:20) at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1138:14)
安裝 electron:github
$ npm install electron -g
Electron 的進程分爲主進程和渲染進程。web
在 electron 裏面,運行 package.json
裏面 main
腳本的進程成爲主進程。主進程控制整個應用的生命週期,在主進程中能夠建立 Web 形式的 GUI,並且整個 Node API 是內置其中。npm
每一個 electron 的頁面都運行着本身的進程,稱爲渲染進程。json
主進程使用 BrowserWindow
實例建立頁面。每一個 BrowserWindow
實例都在本身的渲染進程裏運行頁面。當一個 BrowserWindow
實例被銷燬後,相應的渲染進程也會被終止。
主進程管理全部頁面和與之對應的渲染進程。每一個渲染進程都是相互獨立的,而且只關心他們本身的頁面。
在 electron 中,頁面不直接調用底層 APIs,而是經過主進程進行調用。因此若是你想在網頁裏使用 GUI 操做,其對應的渲染進程必須與主進程進行通信,請求主進程進行相關的 GUI 操做。
在 electron 中,主進程和渲染進程的通訊主要有如下幾種方式:
ipcMain、ipcRender
Remote 模塊
進程通訊將稍後詳細介紹。
如下全部代碼能夠在 https://github.com/nodejh/electron-quick-start 找到。
一個最簡單的 electron 應用目錄結構以下:
electron-demo/ ├── package.json ├── main.js └── index.html
package.json
與 Node.js 的徹底一致,因此咱們可使用 npm init
來生成。而後將 "main": "index.js"
修改成 "main": "main.js"
。之因此命名爲 main.js
,主要是爲了與主進程這個概念對應。
建立 main.js
文件並添加以下代碼:
const electron = require('electron'); const { app, // 控制應用生命週期的模塊 BrowserWindow, // 建立原生瀏覽器窗口的模塊 } = electron; // 保持一個對於 window 對象的全局引用,若是不這樣作, // 當 JavaScript 對象被垃圾回收, window 會被自動地關閉 let mainWindow; function createWindow() { // 建立瀏覽器窗口。 mainWindow = new BrowserWindow({width: 800, height: 600}); // 加載應用的 index.html。 // 這裏使用的是 file 協議,加載當前目錄下的 index.html 文件。 // 也可使用 http 協議,如 mainWindow.loadURL('http://nodejh.com')。 mainWindow.loadURL(`file://${__dirname}/index.html`); // 啓用開發工具。 mainWindow.webContents.openDevTools(); // 當 window 被關閉,這個事件會被觸發。 mainWindow.on('closed', () => { // 取消引用 window 對象,若是你的應用支持多窗口的話, // 一般會把多個 window 對象存放在一個數組裏面, // 與此同時,你應該刪除相應的元素。 mainWindow = null; }); } // Electron 會在初始化後並準備 // 建立瀏覽器窗口時,調用這個函數。 // 部分 API 在 ready 事件觸發後才能使用。 app.on('ready', createWindow); // 當所有窗口關閉時退出。 app.on('window-all-closed', () => { // 在 macOS 上,除非用戶用 Cmd + Q 肯定地退出, // 不然絕大部分應用及其菜單欄會保持激活。 if (process.platform !== 'darwin') { app.quit(); } }); app.on('activate', () => { // 在 macOS 上,當點擊 dock 圖標而且該應用沒有打開的窗口時, // 絕大部分應用會從新建立一個窗口。 if (mainWindow === null) { createWindow(); } });
關於 app
和 BrowserWindow
對象和實例的更多用法可參考 electron 的文檔:
而後編輯須要展現的 index.html
:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Hello World!</title> <style media="screen"> .version { color: red; } </style> </head> <body> <h1>Hello World!</h1> We are using Node.js <span id="version-node" class="version"></span> and Electron <span id="version-electron" class="version"></span> <script type="text/javascript"> console.log('process: ', process); var versionNode = process.version; var versionElectron = process.versions['electron']; document.getElementById('version-node').innerText = versionNode document.getElementById('version-electron').innerText = versionElectron </script> </body> </html>
在這個例子中,咱們顯示出了 electron 使用的 Node.js 版本和 electron 的版本。index.html
跟網頁的 HTML 一摸同樣,只是多了一些 electron 的全局對象。
由於前面已經全局安裝了 electron,因此咱們可使用 electron 命令來運行項目。在 electron-demo/
目錄裏面運行下面的命令:
$ electron .
而後會彈出一個 electron 應用客戶端,如圖所示:
由於在主進程中啓用了開發模式 mainWindow.webContents.openDevTools()
,因此默認啓動開發者工具。
若是是局部安裝的 electron,即 npm install --save electron
,則能夠運行下面的命令來啓動應用:
$ ./node_modules/.bin/electron .
對於 electron 來講,主進程和渲染進程直接的通訊是必不可少的。
前面提到過 electron 進程間的通訊的方式主要有兩種,一種是用於發送消息的 ipcMain 和 ipcRenderer 模塊,一種用於 RPC 的 remote 模塊。
如今假設一個業務場景,用戶在頁面中輸入文本消息,渲染進程將消息發送給主進程,主進程處理後將處理結果返回給頁面。爲了方便起見,主進程的處理就假設爲翻轉文本。固然,這個功能在前端徹底能夠實現,這裏只是爲了演示進程通訊。
首先在渲染進程中添加一個輸入框和一個按鈕,並實現點擊按鈕獲取輸入框的內容。而後使用 ipcRenderer 發送消息。主進程接收到消息並處理以後,會返回處理結果。因此渲染進程中還須要接收主進程的消息。
修改 index.html
,添加下面的代碼:
<!-- 在 body 部分添加一個輸入框和按鈕 --> <div> <input type="text" id="message" name="" value=""> <br/> <button type="button" id="button" name="button">click me</button> </div> <script type="text/javascript"> // ... // 添加下面的代碼。 // 引入 ipcRenderer 模塊。 var ipcRenderer = require('electron').ipcRenderer; document.getElementById('button').onclick = function () { var message = document.getElementById('message').value; // 使用 ipcRenderer.send 向主進程發送消息。 ipcRenderer.send('asynchronous-message', message); } // 監聽主進程返回的消息 ipcRenderer.on('asynchronous-reply', function (event, arg) { alert(arg); }); </script>
接下來在主進程中接收渲染進程的消息,並進行處理(翻轉字符串),而後將處理結果發送給主進程。修改 main.js
以下:
//... // 監聽渲染進程發送的消息 ipcMain.on('asynchronous-message', (event, arg) => { const reply = arg.split('').reverse().join(''); console.log('reply: ', reply); // 發送消息到主進程 event.sender.send('asynchronous-reply', reply); });
而後從新運行項目。在頁面的輸入框內輸入字符,點擊按鈕,就能彈出以下的彈出框,說明渲染進程與主進程通訊成功:
remote 模塊提供了一種在渲染進程(網頁)和主進程之間進行進程間通信(IPC)的簡便途徑。
使用 remote 模塊,咱們能夠很方便地調用主進程對象的方法,而不須要發送消息。
在 index.html
的 <script>
標籤中添加以下代碼:
// 引入 remote 模塊 var remote = require('electron').remote; // 獲取主進程中的 BrowserWindow 對象 var BrowserWindow = remote.BrowserWindow; // 建立一個渲染進程 var win = new BrowserWindow({ width: 200, height: 150 }); win.loadURL('http://nodejh.com');
而後使用 ctr + r
組合鍵刷新應用,就會看到建立出的一個新窗口。
Electron 應用開發完成以後,還須要將其打包成對應平臺的客戶端。經常使用的打包工具備 electron-packager 和 asar。
這裏以 electron-packager 爲例。首先全局安裝 electron-packager:
$ npm install electron-packager -g
而後在項目中安裝 electron:
$ npm install electron --save-dev
而後打包:
$ electron-packager . electron-demo
本文首先對 electron 作了簡單的介紹,而後講解了 electron 進程的概念,其進程包括主進程和渲染進程。而後建立了一個簡單的 electron 應用,並經過實現一個簡單的應用場景,對 electron 進程間的通訊作了實踐。整體來講,使用 electron 建立桌面客戶端的開發體驗跟寫 Node.js 和網頁差很少。但本文對內置模塊好比 app、ipcMain、ipcRender、remote 等的介紹比較粗淺,涉及到一些內置模塊的使用,還須要繼續查詢 electron 的官方文檔,只有實踐越多,才能越熟悉。
--