Electron 提供了一种基于Chrome内核的跨平台桌面APP方案。通过 Electron 可以使用 JavaScript、HTML、CSS 等 Web 技术创建原生应用程序框架。Electron 主要解决了 web 和客户端的交互方案,并提供了大量常用的客户端组件。通过主进程和渲染进程分别管理两端的内容。
基本应用
从开发的角度来看, Electron application 本质上是一个 Node. js 应用程序。 与 Node.js 模块相同,应用的入口是 package.json
文件。 一个最基本的 Electron 应用一般来说会有如下的目录结构:
your-app/
├── package.json
├── main.js
└── index.html
快速创建一个 Electron 应用:
- 安装 electron
npm init
npm install --save-dev electron
修改 package.json 文件,指定 main.js 文件,设置启动命令:
{
"name": "your-app",
"version": "0.1.0",
"main": "main.js",
"scripts": {
"start": "electron ."
}
}
- 实现 main.js 文件
const { app, BrowserWindow } = require('electron')
function createWindow () {
// 创建浏览器窗口
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true
}
})
// 并且为你的应用加载index.html
win.loadFile('index.html')
}
app.whenReady().then(createWindow)
- 实现 HTML 文件
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using node <script>document.write(process.versions.node)</script>,
Chrome <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
</body>
</html>
- 执行 npm run start 启动应用
也可以使用 Electron-vue 脚手架创建基于 vue cli 的应用
通信
混合应用的基本问题之一通信。
Electron 提供了 ipcMain 模块和 ipcRender 模块基于事件监听模式来实现客户端和web 页面的通信。
基本逻辑是在主线程中使用 ipcMain 监听页面的事件请求,并基于event 返回请求结果。事件的基本里流程即 进程1 发起请求-》进程2 响应请求
请求的事件分为同步事件、异步事件,监听的事件分为全局监听和一次性监听。具体实现如下:
主线程
// In main process.
const ipcMain = require('electron').ipcMain;
ipcMain.on('asynchronous-message', function(event, arg) {
console.log(arg); // prints "ping"
event.sender.send('asynchronous-reply', 'pong');
});
ipcMain.on('synchronous-message', function(event, arg) {
console.log(arg); // prints "ping"
event.returnValue = 'pong';
});
ipcMain.once('once-message', function(event, arg) {
console.log(arg); // prints "once"
event.returnValue = 'once';
});
渲染线程
// In renderer process (web page).
const ipcRenderer = require('electron').ipcRenderer;
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')); // prints "pong"
ipcRenderer.on('asynchronous-reply', function(event, arg) {
console.log(arg); // prints "pong"
});
ipcRenderer.send('asynchronous-message', 'ping');
ipcRenderer.send('once-message', 'once');
ipcMain API:
//监听
ipcMain.on(channel, listener)
ipcMain.once(channel, listener)
//移除监听
ipcMain.removeListener(channel, listener)
ipcMain.removeAllListeners([channel])
//event
event.returnValue
event.sender //sender 即 webContents
ipcRender API:
//监听
ipcRenderer.on(channel, listener)
ipcRenderer.once(channel, listener)
//移除
ipcRenderer.removeListener(channel, listener)
ipcRenderer.removeAllListeners([channel])
//发送消息
ipcRenderer.send(channel[, arg1][, arg2][, ...])
ipcRenderer.sendSync(channel[, arg1][, arg2][, ...])
ipcRenderer.sendToHost(channel[, arg1][, arg2][, ...])//不同渲染进程间的通信
注意
- 主进程和渲染进程可以相互通信,渲染进程之间可以相互通信。
- 事件分为同步和异步事件。
- 事件的监听分为一次性和非一次性的。
- 事件可移除。
文件操作
Electron 提供对原生文件对象进行了扩展,为 file 文件添加了 path 属性,方便开发者更灵活的处理文件操作。
比如文件的拖拽保存:
HTML中监听拖拽事件,获取文件后将文件路径传递给主线程,由主线程完成 copy 操作。
const ipcRenderer = require('electron').ipcRenderer;
function saveFile(fielPath,fileName){
ipcRenderer.sendSync('synchronous-message', filePath,fileName);
}
document.addEventListener('drop', (e) => {
e.preventDefault();
e.stopPropagation();
for (const f of e.dataTransfer.files) {
console.log('File(s) you dragged here: ', f.path)
saveFile(f.path,f.name);
}
});
document.addEventListener('dragover', (e) => {
e.preventDefault();
e.stopPropagation();
});
主线程监听 **save-file**
事件,执行copy 操作。
const ipcMain = require('electron').ipcMain;
const fs = require('fs');
const path = require('path');
ipcMain.on('save-file', function(event, filePath,fileName) {
fs.copyFileSync(filePath, path.join(__dirname,'file',fileName));
});