electron学习

工作需要,electron学习(跨平台的桌面应用), 背后(chrome+node)。

1
2
3
4
5
6
7
electron 有两个进程:主进程和渲染进程。模块可以在单个或多个进程上工作。

主进程工作在幕后,而渲染进程工作在你应用程序用户可以看到的每一个窗口。

模块(Modules) Electron 的 API 根据他们的职责被组合到一起。

例如 dialog 这个模块包含了所有本地对话框(打开文件框、提示框)的 API。

理解了electron中主线程和渲染线程的概念,基本上就能用electron开发应用了。

其他的用到的时候 去查electron的api即可。

electron文档: electron Api

前期工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
确保电脑安装了 node 环境。 使用node -v
下载node时 npm(node package manager)也会一并安装了。
npm常用命令:
搜索 npm search electron
下载 npm install --save-dev -g electron, 这里-g为全局安装。
简写 install为 i, --save-dev为 -D, --save为 -S
查看信息 npm info electron 也可以只看一些信息 npm info electron description

1. mkdir helloelectron
2. cd helloelectron
3. npm init
4. npm i -S electron
npm i -D electron-package
5. mkdir src
6. cd src
7. touch main.js 也可直接用vim编辑
8. touch index.html

9.编辑package.json
设置 "main": "src/main.js"
设置一系列脚本 "scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "electron .",
"package": "electron-packager ./ helloElectron --platform=mas --arch=x64 --version=1.8.4 --out=dist/ --overwrite --ignore=node_modules/electron-* --ignore=node_modules/.bin --ignore=.git --ignore=dist --prune"
}
10. 编辑index.html, 随便写写。
11. 编辑main.js 具体code看下面
12. 即可可以运行了 npm run start

在主线程中初始化mainWindow和管理app的生命周期

编辑main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
'use strict'

const { app, BrowserWindow} = require('electron');
const path = require('path');
const url = require('url');

let window;

const createWindow = () => {
window = new BrowserWindow({
width: 800,
height: 600
});

console.log(__dirname);
const URL = url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file',
slashes: true
});

window.loadURL(URL);

// 打开调试
window.webContents.openDevTools();

window.on('closed', () => {
window = null;
});

require('./main/menu.js');
require('./main/index.js');
}

app.on('ready', createWindow);

app.on('window-all-closed', () => {
if(process.platform != 'darwin') {
app.quit();
}
})

app.on('activate', () => {
if(window == null) {
createWindow();
}
})

electron中主进程和渲染进程之间几种通信的方式。

使用ipc进行通信

不要用 ipc 传递大量的数据,会有很大的性能问题,可能会让你整个应用卡住。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
主进程中使用ipcMain
const {ipcMain} = require('electron');
// 主进程在channel=a-id进行监听。
ipcMain.on('a-id', (event, arg) => {
console.log(arg);
// 发送回复 channel=a-id-back
event.sender.send('a-id-back', 'fine. thank you!');
})

ipcMain.on('b-id', (event, arg) => {
console.log(arg)
event.returnValue = 'xixixi';
})


渲染进程中使用ipcRenderer
const {ipcRenderer} = require('electron');
// 获取页面上的button,当button点击时该渲染进程向已经在监听的主进程(channel=a-id)发送消息。
const sendmsg = document.querySelector('#sendmsg');
sendmsg.onclick = () => {
ipcRenderer.send('a-id', 'how are you');
// 在channel=a-id-back进行监听。
ipcRenderer.on('a-id-back', (event, arg) => {
console.log('收到回复')
console.log(arg);
})
}

const sendmsgsync = document.querySelector('#sendmsgsync');
sendmsgsync.onclick = () => {
const returnMsg = ipcRenderer.sendSync('b-id', 'hihihi');
console.log(returnMsg);
}

使用remote模块

直接在渲染进程中使用remote模块,可以获取主进程中模块,从而进行通信。

1
2
3
4
5
6
7
const {BrowserWindow, Menu, MenuItem} = require('electron').remote;
const {dialog} = require('electron').remote;
//获取button对象
const showerrordialog = document.querySelector('#showerrordialog');
showerrordialog.onclick = () => {
dialog.showErrorBox('提示', '资源不存在');
}
主进程向渲染进程发送消息
1
2
3
4
5
6
7
8
在主进程中 使用mainWindow对象
mainWindow.webContents.send('action', 'new'); //点击后向主页渲染进程发送“新建文件”的命令
//监听与主进程的通信
ipcRenderer.on('action', (event, arg) => {
if(arg == 'new') {
console.log('new file...');
}
})

渲染进程之间的通信。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
1. 全局属性
// In the main process.
global.shareObject = {
name: 'dottie'
}
// In page 1.
require('electron').remote.getGlobal('sharedObject').name = 'china'
// In page 2.
console.log(require('electron').remote.getGlobal('sharedObject').name)
此方式不好, 实质的通信功能。

2. 利用主进程做消息中转, 挺好的。
// In the main process.
ipcMain.on('ping-event', (event, arg) => {
mainWindow.webContents.send('pong-event', 'something');
}

// In renderer process1
ipcRenderer.send('ping-event', (event, arg) => {
// do something
}
)

// In renderer process2
ipcRenderer.on('pong-event', (event, arg) => {
// do something
}
)

3. 利用 remote 接口直接获取渲染进程发送消息:
remote.BrowserWindow.fromId(winId).webContents.send('ping', 'someThing');
渲染进程获取 ID 就有多种方法了:

第一种: 通过 global 设置和获取
第二种是: 主进程创建事件,发送信息
// main process
win1.webContents.send('distributeIds',{
win2Id : win2.id
});
win2.webContents.send('distributeIds',{
win1Id : win1.id
});

##体外话。

基本上,现在都直接写ES6的代码,但是浏览器目前只支持到es5.

那么需要借助于其他工具来完成 es6 转 es5

那么babel就出现了

babel-cli提供的babel转换成ES5或者使用babel-node直接运行ES6的代码。

npm install babel-cli -g 全局安装
babel-cli有两个主要的命令需要用到:

babel:按照“.babelrc“文件转码js文件。

babel-node:提供一个支持ES6的REPL环境,支持Node的REPL环境的所有功能,可以直接运行ES6代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
除此之外, 光有babel是不行的(会直接原封不动的输出)。 还要安装插件(es6转es5的编译规则)

npm install babel-preset-es2015 --save-dev

然后在项目根目录下新建.babelrc
{
"presets": [
"es2015"
],
"plugins": []
}

最后就可以用babel进行转换了。
babel index-es6.js -o index-es5.js
babel src -d app //将src目录下所有js文件 转换输出到app目录下。

当然了你可以写在package.json的scripts中
"make":"babel src -d app"
然后就可以直接npm run make即可。

或者:
直接输入babel-node命令,可以在命令行中直接运行ES6代码