参考electron文档: www.electronjs.org/docs
简介
electron是由Github开发,是一个用Html、css、JavaScript来构建桌面应用程序的开源库,可以打包为Mac、Windows、Linux系统下的应用。
核心
Electron 包含三个核心:
-
Chromium为Ele ctron 提供强大的UI能力,可以在不考虑兼容性的情况下开界面 -
Node.js用于本地文件 系统和操作系 统 -
系统API为了提供原生系统的GUI支持,Electron内置了原生应用程序接口,对调用一些系统功能,如调用系统通知、打开系统文件夹提供支持。
可以理解为,electron是一个得到了Node.js和基于不同平台的Native APIs加强的Chromium浏览器,可以用来开发跨平台的桌面级应用
为什么选择electron
优点:
跨平台
- 上手难度低。能够使用react、vue等前端框架,能方便地迁移前端组件,构建出漂亮的桌面应用。
- 是目前最廉价的跨平台技术方案,HTML+JS 有大量的前端技术人员储备,而且有海量的现存web UI 库。
- Electron由github主导,有成熟的产品atom和vs code,Intel和微软都有参与,社区更活跃。
缺点:
- 应用体积过大。为了实现跨平台,它将整个V8引擎和Chromium内核都打包进去,在mac上至少是45M+起步,在windows上稍微好一点,不过也要35M+起步。不过相比早期打包体积100M+起步来说,已经好了不少。不过解压后安装依然是100M+起步。
- 应用性能依旧是个问题。
有哪些著名应用是用Electron开发的
- VSCode : 程序员最常用的开发者工具。 Atom : 是Github开发的文本编辑器。
- slack : 聊天群组 + 大规模工具集成 + 文件整合 + 搜索的一个工具。就是把很多你常用的工具整合到了一起。
- wordPress : 基于PHP开发的Blog搭建工具,新版本使用了Electron.
安装
cnpm install -g electron //全局安装 electron
npx electron -v // 版本查看
大体上,一个 Electron 应用的目录结构如下:
my-electron-app/
├── index.html
├── main.js
└── package.json
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
const { app, BrowserWindow } = require('electron')
let mainWindow = null
app.on('ready', () => { // 监听准备事件
mainWindow = new BrowserWindow({
height: 500,
width: 500,
webPreferences: { //允许使用node的API
nodeIntegration: true
}
})
mainWindow.loadFile('index.html')
mainWindow.on('closed', () => { // 监听关闭时间
mainWindow = null // 监听窗口关闭时销毁,否则的话内存会一直被占用
})
})
{
"name": "electron-demo",
"version": "0.0.1",
"description": "electron-demo",
"main": "main.js",
"author": "sakurako",
"scripts": {
"start": "electron ."
}
}
Electron 应用程序使用package.json文件作为主入口(像任何其它的 Node.js 应用程序)。 应用程序的主脚本是main.js,所以相应修改package.json文件:
进程
Main主进程
主要通过Node.js、Chromium和Native APIs来实现一些系统以及底层的操作, 一些只能或适合在主进程做的事情。例如创建APP的窗口、创建系统级别的菜单、操作剪贴板、全局快捷键处理、托盘等。
app、BrowserWindow、ipcMain、Menu、Tray、dialog、Notification、webContents、globalShortcut、autoUpdater等。
Renderer渲染进程
主要通过Chromium来实现APP的图形界面——就是平时我们熟悉的前端开发的部分 一个主进程可以多个渲染进程 ipcRenderer、desktopCapture等。
Electron生命周期:
app的常用生命周期钩子:
will-finish-launching在应用完成基本启动进程之后触发ready当electron完成初始化后触发;window-all-closed所有窗口都关闭的时候触发,在windows和linux里,所有窗口都退出的时候通常是应用退出的时候before-quit退出应用之前的时候触发will-quit所有窗口都已经关闭,即将退出应用的时候触发quit应用退出的时候触发- ...
而我们通常会在ready的时候执行创建应用窗口、创建应用菜单、创建应用快捷键等初始化操作。而在will-quit或者quit的时候执行一些清空操作,比如解绑应用快捷键。
跟app模块一样,BrowserWindow也有很多常用的事件钩子:
closed当窗口被关闭的时候focus当窗口被激活的时候show当窗口展示的时候hide当窗口被隐藏的时候maxmize当窗口最大化时minimize当窗口最小化时- ...
针对不同的业务逻辑你需要对窗口进行不一样的操作。这个需要跟你的项目需求相匹配。比如上述说到的,windows的顶部的操作区(放大、缩小、关闭按钮)就可以通过icon模拟+实例方法来实现。
web-Contents生命周期事件 使用:mainWindow.webContents.on('事件名',回调);
配置:
- 热加载 安装electron-reloader
npm install electron-reloader --save-dev
在主进程js文件(main.js/index.js)加入如下代码:
try {
require('electron-reloader')(module);
} catch (_) { }
- Electron 打开开发者工具 devtools 在主进程main.js加入如下代码:
mainWindow.webContents.openDevTools({mode:'right'});
主进程渲染进程之间的通讯
- ipcMain 从主进程到渲染进程的异步通信。
- ipcRenderer 从渲染器进程到主进程的异步通信。
- BrowserWindow webContents结合主进程实现渲染进程和渲染进程通信
ipcMain & ipcRenderer
// 在主进程中.
const { ipcMain } = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg) // prints "ping"
event.reply('asynchronous-reply', 'pong')
})
//在渲染器进程 (网页) 中。
const { ipcRenderer } = require('electron')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"
ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log(arg) // prints "pong"
})
ipcRenderer.send('asynchronous-message', 'ping')
注意:ipcMain无法主动发消息给ipcRenderer。因为ipcMain只有.on()方法没有.send()的方法。所以只能用其他方法来实现,webContents。
webContents
webContents其实是BrowserWindow实例的一个属性。也就是如果我们需要在main进程里给某个窗口某个页面发送消息,则必须通过win.webContents.send()方法来发送。
代码大致如下:
// In main process
let win = new BrowserWindow({...})
win.webContents.send('img-files', imgs)
// In renderer process
ipcRenderer.on('img-files', (event, files) => {
console.log(files)
})
所以必须指定要发送的窗口,才能将信息准确送达。
常用的一些api
通知Notification
从主进程中引入Notification类
- title: 通知的标题,可以显示在通知栏上
- option: 消息通知的各种属性配置,以对象的形式进行配置。
const { Notification } = require('electron')
function showNotification ()
const notification = {
title: '标题',
body: '内容'
}
new Notification(notification).show()
}
app.whenReady().then(createWindow).then(showNotification)
托盘
当主进程监听关闭事件时,这时我们就可以开启托盘功能。我们需要使用Electron的两个模块Menu与Tray。
const { app, Menu, Tray } = require('electron')
let tray = null
app.whenReady().then(() => {
tray = new Tray('/path/to/my/icon')
const contextMenu = Menu.buildFromTemplate([
{ label: 'Item1', type: 'radio' },
{ label: 'Item2', type: 'radio' },
{ label: 'Item3', type: 'radio', checked: true },
{ label: 'Item4', type: 'radio' }
])
tray.setToolTip('This is my application.')
tray.setContextMenu(contextMenu)
})
托盘闪烁
let timer=setInterval(function() {
count++;
if (count%2 == 0) {
appIcon.setImage(path.join(__dirname,'empty.ico'))
} else {
appIcon.setImage(path.join(__dirname,'lover.png'))
}
}, 500);
弹出框 dialog
//下面是一个选择多个文件的对话框示例:
const { dialog } = require('electron') //渲染进程 const { dialog } = require('electron').remote
console.log(dialog.showOpenDialog({ properties: ['openFile', 'multiSelections'] }))
自定义软件顶部菜单、自定义右键菜单
创建菜单menu.js
主进程require
let template = [{
label: 'Edit',
submenu:[
{
label:'item1',
click:function(){}
},
{
type: 'separator'
}
],
}];
const menu = Menu.buildFromTemplate(template) // 根据template生成一个Menu对象
Menu.setApplicationMenu(menu) // 根据menu生成菜单
剪切板
const { clipboard } = require('electron')
clipboard.writeText('Example String', 'selection')
console.log(clipboard.readText('selection'))
var app = require('app');
var globalShortcut = require('electron').globalShortcut;
app.on('ready', function() {
// Register a 'ctrl+x' shortcut listener.
var ret = globalShortcut.register('ctrl+x', function() {
console.log('ctrl+x is pressed');
})
if (!ret) {
console.log('registration failed');
} // Check whether a shortcut is registered.
console.log(globalShortcut.isRegistered('ctrl+x'));
});
app.on('will-quit', function() {
// Unregister a shortcut.
globalShortcut.unregister('ctrl+x');
// Unregister all shortcuts.
globalShortcut.unregisterAll();
});
离线上线监听
其实这个是JavaScript的一种方式进行监听网络状态,监听的事件分别是online和offline。
- online : 如果链接上网络,就会触发该事件。
- offline : 如果突然断网了,就会触发该事件。
const alertOnlineStatus = () => { window.alert(navigator.onLine ? 'online' : 'offline') }
window.addEventListener('online', alertOnlineStatus)
window.addEventListener('offline', alertOnlineStatus)
alertOnlineStatus()
electron 打包
- electron-packager 打包完成的是可执行文件。
- electron-builder 打包完成的是安装包。有更丰富的的功能,支持更多的平台,支持自动更新,打出的包更为轻量,并且可以打包出不暴露源码的setup安装程序。
npm install electron-builder --save-dev
npm install electron-builder -g
electron-builder --version
electron-builder
"build": {
"appId": "com.leon.HelloWorld02",//包名
"copyright":"LEON",//版权
"productName":"HelloWorld02",//项目名
"dmg":{
"background":"res/background.png",//背景图片路径
"window":{
//窗口左上角起始坐标
"x":100,
"y":100,
//窗口大小
"width":500,
"height":300
}
},
"win": {
"icon": "res/icon.ico"//图标路径
}
}
打包可能遇到的报错: blog.csdn.net/q1059997113…
打包优化: 缩减包体积
electron应用的更新
electron应用的自动更新其实社区有很好的解决方案electron-updater。而electron-vue也在主进程的main/index.js里预先帮我们写好了一段注释的代码:
// import { autoUpdater } from 'electron-updater'
// autoUpdater.on('update-downloaded', () => {
// autoUpdater.quitAndInstall()
// })
// app.on('ready', () => {
// if (process.env.NODE_ENV === 'production') {
// autoUpdater.checkForUpdates()
// }
// }
electron-vue
- 只有一个package.json。而大部分其他的项目结构依然在使用两个package.json来应对main进程和renderer进程的依赖库。
- 内建完整的vue全家桶,省去再次配置vue-router和vuex的一些初期操作。
- 内建完整的webpack开发、生产等配置,开发环境舒适。
- 内建完整的开发、构建等npm scripts,使用非常方便。
- 内建完整的Travis-ci、Appveyor配置脚本,只需少数修改就能做到利用CI自动构建的应用发布。
- 完善的文档,清晰的项目结构
安装
# 如果你没有vue-cli的话需要全局安装
npm install -g vue-cli
# 然后使用vue-cli来安装electron-vue的模板
vue init simulatedgreg/electron-vue my-project
# 安装依赖
cd my-project
yarn # or npm install
# 进入开发模式
yarn run dev # or npm run dev
安装成功后
my-project
├─ .electron-vue
│ └─ <build/development>.js files
├─ build
│ └─ icons/
├─ dist
│ ├─ electron/
│ └─ web/
├─ node_modules/
├─ src
│ ├─ main # 主进程
│ │ ├─ index.dev.js
│ │ └─ index.js
│ ├─ renderer # 渲染进程
│ │ ├─ components/
│ │ ├─ router/
│ │ ├─ store/
│ │ ├─ App.vue
│ │ └─ main.js
│ └─ index.ejs
├─ static/
├─ test
│ ├─ e2e
│ │ ├─ specs/
│ │ ├─ index.js
│ │ └─ utils.js
│ ├─ unit
│ │ ├─ specs/
│ │ ├─ index.js
│ │ └─ karma.config.js
│ └─ .eslintrc
├─ .babelrc
├─ .eslintignore
├─ .eslintrc.js
├─ .gitignore
├─ package.json
└─ README.md
传送门: electron-vue文档 electron-vue,作者为我们封装好了一个基于vue框架的脚手架,包括electron所有基本的开发构建工具 和vue配套的请求,路由以及vuex等插件。通过脚手架我们可以直接进入开发阶段,开发的同时,去了解electron的工作机制,之后再开始深入去理解她更深层次的代码逻辑。 先走形,再走心。