1. 简介
- 官网
- Electron是由GitHub开发,使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序
- Electron 可以让你使用纯 JavaScript 调用丰富的原生 APIs 来创造桌面应用。你可以把它看作是专注于桌面应用
- 在PC端混合app开发中,nwjs和electron都是可选的方案,它们都是基于Chromium和Node的结合体, 而electron相对而言是更好的选择方案,它的社区相对比较活跃,bug比较少,文档先对利索简洁。
- electron 相对来说比 nw.js 靠谱。有一堆成功的案例:Atom 编辑器 2. Slack (那个独角兽公司)3. Visual Studio Code 4. WordPress 等等。。
- Node. js 的所有 内置模块 都在Electron中可用, 第三方 node 模块中也完全支持 (包括 原生模块 )。
- Electron 还为开发原生桌面应用程序提供了一些额外的内置模块。 某些模块仅在主进程中可用, 有些仅在渲染进程 (web 页) 中可用, 而有些在这两个进程中都可以使用。
2. 五分钟快速上手
2.1 安装electron
- npm init
- cnpm I electron –S
- npx electron
2.2 配置为入口文件
{
"name": "electron-demo",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "electron ."
},
"author": "",
"license": "ISC",
"dependencies": {
"electron": "^8.3.0"
}
}
2.3 创建main.js文件
const electron = require('electron')
const app = electron.app
app.on('ready', ()=>{
new electron.BrowserWindow({
width: 800,
height: 300
})
})
2.4创建窗口
app.on('ready', ()=>{
const mainWindow = new BrowserWindow({
width: 800,
height: 500
})
mainWindow.loadFile('./index.html')
})
3. 主进程和渲染进程
Electron 运行 package.json
的 main
脚本的进程被称为主进程。 在主进程中运行的脚本通过创建web页面来展示用户界面。 一个 Electron 应用总是有且只有一个主进程。
由于 Electron 使用了 Chromium 来展示 web 页面,所以 Chromium 的多进程架构也被使用到。 每个 Electron 中的 web 页面运行在它的叫渲染进程的进程中。
在普通的浏览器中,web页面无法访问操作系统的原生资源。 然而 Electron 的用户在 Node.js 的 API 支持下可以在页面中和操作系统进行一些底层交互。
ctrl+shift+i打开渲染进程调试
app.on('ready', ()=>{
const mainWindow = new BrowserWindow({
width: 800,
height: 500
})
mainWindow.loadFile('./index.html')
const mainWindow2 = new BrowserWindow({
width: 800,
height: 500
})
mainWindow2.loadFile('./index2.html')
})
4. 自定义原生菜单
4.1 自定义菜单
const electron = require('electron')
const { app, Menu } = electron
const template = [
{
label: '文件',
submenu: [
{
label: '新建窗口'
}
]
},
{
label: '编辑',
submenu: [
{
label: '新建窗口'
}
]
}
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
4.2 给菜单定义点击事件
1、点击打开新窗口
submenu: [
{
label: '新建窗口',
click: ()=>{
const newMainWindow = new BrowserWindow({
width: 300,
height: 300
})
newMainWindow.loadFile('./new.html')
}
}
]
2、点击打开浏览器
const { BrowserWindow, Menu, shell } = require('electron')
const template = [
{
label: '文件',
submenu: [
{
label: '文件1',
click () {
// 点击打开新窗口
const mainWindow2 = new BrowserWindow({
width: 600,
height: 600
})
mainWindow2.loadFile('./index.html')
}
}
]
},
{
label: 'csdn',
click () {
// 点击打开浏览器
shell.openExternal('')
}
}
]
4.3 抽离菜单定义
const { BrowserWindow, Menu} = require('electron')
const template = [
{
label: '文件',
submenu: [
{
label: '新建窗口',
click: ()=>{
const newMainWindow = new BrowserWindow({
width: 300,
height: 300
})
newMainWindow.loadFile('./new.html')
}
}
]
},
{
label: '编辑',
submenu: [
{
label: '新建窗口'
}
]
}
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
require('./menu')
打开调式
mainWindow.webContents.openDevTools()
4.4 自定义顶部菜单
- 通过frame创建无边框窗口
const mainWindow = new electron.BrowserWindow({
frame: false
})
- 自定义窗口
<div class="header" style="-webkit-app-region: drag;">
</div>
- icon
const mainWindow = new electron.BrowserWindow({
width: 1000,
height: 600,
webPreferences: {
nodeIntegration: true
},
frame: false,
icon: './hm.ico'
})
- backgroundColor
4.5 定义右键菜单
js>index.js
const { remote } = require('electron')
const template = [
{
label: '粘贴'
},
{
label: '赋值'
}
]
const menu = remote.Menu.buildFromTemplate(template)
window.addEventListener('contextmenu', (e) => {
console.log(123)
e.preventDefault()
menu.popup({ window: remote.getCurrentWindow() })
})
在index.html中引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button>打开新的窗口</button>
<script src="./js/index.js"></script>
</body>
</html>
能够在html中使用node方法
const mainWindow = new BrowserWindow({
width: 800,
height: 500,
webPreferences: {
nodeIntegration: true
}
})
4.6 点页面打开浏览器
- html
<a id="a1" href="">打开浏览器</a>
- js
const { shell } = require('electron')
const allA = document.querySelectorAll('a')
allA.forEach(item => {
item.onclick = function (e) {
e.preventDefault()
console.log(item)
shell.openExternal(item.href)
}
})
5. 自动刷新页面
- 安装插件
cnpm install --save-dev electron-reloader
- 在入口引入插件
const reloader = require('electron-reloader')
reloader(module,{})
6. 拖拽文件进行读取
- 定义拖拽到指定区域
<div id="drop">
</div>
#drop {
width: 300px;
height: 500px;
background: hotpink;
}
- 添加拖拽事件获取文件路径
// 添加拖拽
const dropEl = document.querySelector('#drop')
dropEl.addEventListener('drop', function(e) {
if(e.dataTransfer.files.length === 1) {
const filePath = e.dataTransfer.files[0].path
}
})
dropEl.addEventListener('dragover', function (e) {
e.preventDefault()
})
- 引入fs模块进行读取
const fs = require('fs')
// 添加拖拽
const dropEl = document.querySelector('#drop')
dropEl.addEventListener('drop', function(e) {
if(e.dataTransfer.files.length === 1) {
const filePath = e.dataTransfer.files[0].path
const fileContent = fs.readFileSync(filePath).toString()
this.innerText = fileContent
}
})
dropEl.addEventListener('dragover', function (e) {
e.preventDefault()
})
7. 打开对话框
7.1 读取文件
- 定义点击事件
<button onclick="openFile()">打开</button>
- 定义事件函数
// 打开对话框
function openFile() {
const res = remote.dialog.showOpenDialogSync({
title: '选择文件',
buttonLabel: '哈哈',
filters: [
{ name: 'Custom File Type', extensions: ['js','html','json'] },
]
})
const fileContent = fs.readFileSync(res[0]).toString()
dropEl.innerText = fileContent
}
7.2 保存文件
- 定义点击事件
<button onclick="saveFile()">保存</button>
- 事件函数
// 保存对话框
function saveFile() {
const res = remote.dialog.showSaveDialogSync({
title: '保存文件',
buttonLabel: '保存文件',
filters: [
{ name: 'index', extensions: ['js'] },
]
})
fs.writeFileSync(res, 'hahhdasdshafsdahjk')
}
8. 消息提示
- 定义事件
<button onclick="messageBox()">提示</button>
- 事件函数
// 提示信息
function messageBox() {
remote.dialog.showMessageBoxSync({
type: 'none',
buttons: ['确定'],
title: '提示消息',
message: '明天会下雨呦'
})
}
9. 定义快捷键
9.1 主线程定义
- 引入
const { app, BrowserWindow, globalShortcut } = require('electron')
- 在ready中注册快捷键
const { app, BrowserWindow, globalShortcut } = require('electron')
9.2 渲染进程定义
- 通过remote注册
// 定义快捷键
remote.globalShortcut.register('Ctrl+O', () => {
console.log('ctrl+o')
})
- 定义快捷键最大、最小、关闭窗口
globalShortcut.register('Ctrl+T',()=>{
mainWindow.unmaximize();
})
globalShortcut.register('Ctrl+H',()=>{
mainWindow.close()
})
globalShortcut.register('Ctrl+M',()=>{
mainWindow.maximize()
})
10. 渲染进程和主线程通讯
- 定义按钮
<div class="maxWindow no-drag" onclick="maxWindow()"></div>
- 事件函数
function maxWindow() {
ipcRenderer.send('max-window')
}
- 主线程定义事件
ipcMain.on('max-window', () => {
mainWindow.maximize()
})
- 传参
let windowSize = 'unmax-window'
function maxWindow() {
windowSize = windowSize === 'max-window' ?'unmax-window':'max-window'
ipcRenderer.send('max-window',windowSize)
}
- 接收参数
ipcMain.on('max-window', (event,arg) => {
console.log(arg)
if(arg === 'unmax-window') return mainWindow.maximize();
mainWindow.unmaximize()
})
- 通过isMaximized判断当前窗口
11. 网络请求
async function getMsg () {
const res = await fetch('http://127.0.0.1:3006/api/person').then(res=>res.json())
console.log(res)
}
12 .electron结合框架开发
12.1 结合react
利用react初始化项目
- npx create-react-app electron-react
- cd electron-react
- npm start
安装electron
- cnpm i electron
- 添加electron的任务
"main": "main.js",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"electron": "electron ."
},
- 添加main.js https://github.com/electron/electron-quick-start/blob/master/main.js
const {app, BrowserWindow} = require('electron')
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600
})
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
app.whenReady().then(() => {
createWindow()
})
- 加载react项目
mainWindow.loadURL('http://localhost:3000/')
12.2 electron结合vue
同react
13 electron打包
- 将vue项目打包
- 修改electron引入的文件
mainWindow.loadFile('./dist/index.html')
- 安装electron-packager
"packager": "electron-packager ./ HelloWorld --platform=win32 --arch=x64 --out ./outApp --overwrite --icon=./favicon.ico"