#1. 简介
- 官网
- Electron是由GitHub众多开发者开发的一个开源项目,能够使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序
2. 五分钟快速上手
2.1 安装electron
初始化package.json文件
- npm init
安装electron
- cnpm I electron –S
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"
}
}
创建index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
2.3 创建main.js文件
// main.js
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
const path = require('path')
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,//使用node模块及api
contextIsolation: false,
enableRemoteModule: true // 使用remote模块
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.打开调试
// mainWindow.webContents.openDevTools()
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
// In this file you can include the rest of your app's specific main process
// code. 也可以拆分成几个文件,然后用 require 导入。
2.4创建窗口
在 Electron 中,只有在 app 模块的 ready 事件被激发后才能创建浏览器窗口。 您可以通过使用 app.whenReady() API来监听此事件。 在whenReady()成功后调用createWindow()。app.whenReady()和app.on(‘ready’,()=>{})一样
app.on('ready', ()=>{
const mainWindow = new
({
width: 800,
height: 500
})
mainWindow.loadFile('index.html')
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
3. 自动刷新页面
-
安装插件
cnpm install --save-dev electron-reloader
-
在入口引入插件
const reloader = require('electron-reloader') reloader(module)
4. 主进程和渲染进程
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
})
mainWindow.webContents.openDevTools()
mainWindow2.loadFile('./index2.html')
})
5. 自定义原生菜单
5.1 自定义菜单
详细文档:https://www.electronjs.org/docs/api/menu
const electron = require('electron')
const { app, Menu } = electron
const template = [
{
label: '文件',
submenu: [
{
label: '新建窗口'
}
]
},
{
label: '编辑',
submenu: [
{
label: '新建窗口'
}
]
}
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
5.2 给菜单定义点击事件
1、点击打开新窗口
submenu: [
{
label: '新建窗口',
click: ()=>{
const newMainWindow = new BrowserWindow({
width: 300,
height: 300
})
newMainWindow.loadFile('./new.html')
}
}
]
2、点击打开浏览器
shell
模块提供了集成其他桌面客户端的关联功能.
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('https://www.csdn.net/')
}
}
]
5.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()
5.4 自定义顶部菜单
-
通过frame创建无边框窗口
const mainWindow = new electron.BrowserWindow({ frame: false })
-
自定义窗口
<div class="custom-menu"> <ul> <li>新建窗口</li> <li>关于我们</li> </ul> </div>
* { margin: 0; padding: 0; } .custom-menu { height: 50px; width: 100%; background: pink; } .custom-menu ul { list-style: none; } .custom-menu ul li { float: left; width: 50px; line-height: 50px; text-align: center; margin-left: 10px; }
添加-webkit-app-region: drag;实现拖拽
5.5 点击创建新窗口
// html
<li class="new-window">新建窗口</li>
// js
// remote 通过remote使用主进程的方法
const { remote: {BrowserWindow} } = require('electron')
const newWindow = document.querySelector('.new-window')
newWindow.onclick = function () {
new BrowserWindow({
width: 200,
height: 300
})
}
能够在html中使用node方法
const mainWindow = new BrowserWindow({
width: 800,
height: 500,
webPreferences: {
// 开启node模块
nodeIntegration: true,
// 开启remote模块
enableRemoteModule: true
}
})
5.6 点页面打开浏览器
-
html
<a id="a1" href="https://www.itheima.com">打开浏览器</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) } })
6. 打开对话框读取文件
6.1 读取文件
-
定义点击事件
<button onclick="openFile()">打开</button>
-
定义事件函数
打开对话框文档:https://www.electronjs.org/docs/api/dialog
// 打开对话框 function openFile() { const res = dialog.showOpenDialogSync({ title: '选择文件', buttonLabel: '哈哈', filters: [ { name: 'Custom File Type', extensions: ['js'] }, ] }) const fileContent = fs.readFileSync(res[0]) dropEl.innerText = fileContent }
6.2 保存文件
-
定义点击事件
<button onclick="saveFile()">保存</button>
-
事件函数
// 保存对话框 function saveFile() { const res = remote.dialog.showSaveDialogSync({ title: '保存文件', buttonLabel: '保存文件', filters: [ { name: 'index', extensions: ['js'] }, ] }) fs.writeFileSync(res, dropEl.value) }
7. 定义快捷键
7.1 主线程定义
-
引入
const { app, BrowserWindow, globalShortcut } = require('electron')
-
在ready中注册快捷键
const ret = globalShortcut.register('CommandOrControl+X', () => { console.log('CommandOrControl+X is pressed + 打印结果在命令行') })
-
定义快捷键最大、最小、关闭窗口
globalShortcut.register('CommandOrControl+T',()=>{ mainWindow.unmaximize(); }) globalShortcut.register('CommandOrControl+H',()=>{ mainWindow.close() }) globalShortcut.register('CommandOrControl+M',()=>{ mainWindow.maximize() })
7.2 渲染进程定义
-
通过remote注册
// 定义快捷键 remote.globalShortcut.register('Ctrl+O', () => { console.log('ctrl+o') })
8. 渲染进程和主线程通讯
-
定义按钮
<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() })
09. electron打包
-
安装electron-packager
cnpm i electron-packager -D
-
添加打包任务
"build": "electron-packager ./ HelloWorld --platform=win32 --arch=x64 --out ./outApp --overwrite --icon=./favicon.ico"
10 .electron结合框架开发
-
利用vue脚手架初始化项目
-
在项目中安装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
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.on('ready', () => { createWindow() })
-
加载vue项目
mainWindow.loadURL('http://localhost:3000/')
其他
主进程可以使用的模块
app模块 : 控制整个应用的生命周期设计
autoUpdater模块 : 自动更新应用
BrowserWindow模块 : 创建一个浏览器窗口
contentTracing模块 : 收集由底层的Chromium content 模块 产生的搜索数据
dialog模块 : 提供一个弹出框或者文件选择框
globalShortcut模块 : 注册全局的自定义快捷键
ipcMain模块 : 提供主进程和渲染进程之间的通讯方法,接收渲染进程发射过来的事件和数据并进行回复
Menu模块 : 创建鼠票右键显示菜单,跟menuItem 模块配合使用 可以通过remote 模块给渲染的进程调用
powerSaveBlocker模块 : 阻止应用系统进入睡眠模式,允许应用保持系统和屏继续工作
session模块 : 创建一个新的Session对象,可为应用创建多个Cookie文件夹存储不同的数据信息,并且不会相互影响,积压自独立
webContents模块 : 是一个事件发出者,负责渲染并控制网页,也是BrowserWindow对象的属性,可设置打开调试窗口等。
渲染进程可以使用的模块
desktopCapturer 模块:获取可用资源,这个资源可以通过 getUserMedia 捕获得到
ipcRenderer 模块: 提供渲染进程之间的通试方法,可以从渲染进程向主进程发送同步或异步消息,也可以收到主进程相应
remote 模块: 使渲染进程可以调用主进程的模块
webFrame 模块 : 自定义如何渲染当前网页
两个进程都可以使用的模块
clipboard 模块: 提供方法来供复制和粘贴操作
crashReporter 模块: 开启发送应用崩溃报告,自动提交崩溃报告给服务器
nativeImage 模块: 图片对象,从剪切板中读取图片,它返回的是nativeImage
screen 模块: 屏幕的size,显示,鼠标位置等信息,即可根据用户显示器大小等信息进行渲染页面
shell 模块: 提供了集成其他桌面客端的关联功能,如果调用用户默认浏览器打开一个新窗口等