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 的官方文档,只有实践越多,才能越熟悉。
--