安装
npm init
cnpm i electron
在package.json
中指定启动命令
"scripts": {
"dev": "electron ."
},
然后根据入口文件名称创建对应的文件,写入最简单的代码
const { app, BrowserWindow } = require('electron')
app.on('ready', () => {
let mainWindow = new BrowserWindow({
width: 500,
height: 300
})
})
加载资源
// 加载网络资源
mainWindow.loadURL('http://xxxx')
// 加载本地资源
mainWindow.loadFile('src/index.html')
全屏打开及关闭事件
const { app, BrowserWindow } = require('electron')
app.on('ready', () => {
let mainWindow = new BrowserWindow({
// 完全关闭菜单栏
frame: false
})
// 设置窗口为全屏
mainWindow.setFullScreen(true)
// 加载网络资源
mainWindow.loadURL('http://localhost:7981/')
// 当窗口关闭时调用的方法
mainWindow.on('closed', function () {
console.log('close win');
mainWindow = null
})
})
控制台
打开调试控制台配置
// 打开控制台
mainWindow.webContents.openDevTools()
关闭控制台警告
在main.js
中加入
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
注意:需要在打开控制台之前执行
自定义菜单
const { app, BrowserWindow, Menu } = require('electron')
app.on('ready', () => {
const mainWindow = new BrowserWindow({
width: 800,
height: 500,
})
// 加载本地资源
mainWindow.loadFile('src/index.html')
Menu.setApplicationMenu(Menu.buildFromTemplate([
{
label: '同步云端',
submenu: [
{
label: '同步到Gitee',
click() {
console.log('点击事件');
}
}
]
},
{
label: '发布笔记'
}
]))
})
完全自定义头部
先关闭菜单栏
const { app, BrowserWindow } = require('electron')
app.on('ready', () => {
const mainWindow = new BrowserWindow({
width: 800,
height: 500,
frame: false // 完全关闭菜单栏
})
// 加载本地资源
mainWindow.loadFile('src/index.html')
})
然后自己写菜单栏并实现可拖拽
<style>
body {
margin: 0;
}
.header {
width: 100%;
height: 60px;
background-color: aquamarine;
/* 窗口可拖拽 */
-webkit-app-region: drag;
}
.header span {
/* 关闭拖拽防止影响点击事件 */
-webkit-app-region: no-drag;
}
</style>
<body>
<div class="header">
<span>保存</span>
<span>新建</span>
</div>
</body>
</html>
渲染进程
除了入口js文件外都属于渲染进程,一个程序只有一个主进程,而渲染进程要使用Node相关的命令和语法,需要进行配置
const mainWindow = new BrowserWindow({
width: 800,
height: 500,
webPreferences: {
// 开启渲染进程使用Node
nodeIntegration: true,
// 控制上下文隔离
contextIsolation: false,
}
})
然后就可以在子进程中使用
const { shell } = require('electron')
// 所有a标签使用浏览器打开
let allA = document.querySelectorAll('a')
allA.forEach(item => {
item.onclick = function (e) {
e.preventDefault()
shell.openExternal(item.href)
}
})
使用fs
const fs = require('fs')
渲染进程与主进程通信
注意需要先配置webPreferences,上一步有说明
const { ipcMain } = require('electron')
// 自定义事件
ipcMain.on('event-name', (event, arg) => {
console.log(event);
console.log(arg);
mainWindow.maximize()
})
// 触发事件,在使用的页面加引入,支持Vue等
const { ipcRenderer } = require('electron')
ipcRenderer.send('event-name', '传递参数')
主进程可以使用回调给渲染进程传数据
// 主进程
ipcMain.on('marked', (e, a) => {
mainWindow.webContents.send('back-html', marked.parse(a))
})
// 渲染进程
ipcRenderer.on('back-html', (e, a) => {
console.log(a);
})
打包
下载打包依赖
cnpm i electron-packager
然后配置打包命令
"build": "electron-packager ./ my-app --platform=win32 --arch=x64 --out ./target --overwrite --icon=./favicon.ico --electron-zip-dir=D:/Bb_work/electron"
// 32位
"build": "electron-packager ./ my-app --platform=win32 --arch=ia32 --out ./target --overwrite --icon=./favicon.ico --electron-zip-dir=D:/Bb_work/electron"
最后指定了打包源文件的位置,防止因网络问题无法打包,点击前往下载地址
注意:如果打包报错一下信息:
Failed to locate module "cross-spawn" from "D:\La_temp\900\node_modules\cross-env"
This normally means that either you have deleted this package already somehow (check your ignore settings if using electron-packager). Or your module installation failed.
代表npm在下载依赖时只是下载了第一层的依赖,内部依赖并没有下载,进入一级依赖内执行npm i
为其下载才能解决
使用JQ
<script src="lib/jquery.min.js"></script>
<script>if (typeof module === 'object') { window.jQuery = window.$ = module.exports; };</script>
窗口大小/关闭控制
// 关闭窗口
ipcMain.on('win-close', (e, a) => {
mainWindow.close()
})
// 最大化窗口
ipcMain.on('win-max', (e, a) => {
mainWindow.maximize()
})
// 恢复窗口大小
ipcMain.on('win-res', (e, a) => {
mainWindow.restore()
})
// 最小化窗口
ipcMain.on('win-min', (e, a) => {
mainWindow.minimize()
})
如果不想让可拖拽的元素双击最大化可以关闭,在主文件窗口配置中
// 禁用双击最大化窗口,自己控制
maximizable: false
结合Vite
创建vite项目
# npm 7+, extra double-dash is needed:
npm create vite@latest my-vue-app -- --template vue
npm i
安装各种依赖
cnpm i electron concurrently wait-on cross-env electron-packager
其中:concurrently
用于多命令执行,加入wait-on
实现热更新,cross-env
用于指定开发环境和生产环境,electron-packager
用于打包
配置
第一步:创建electron
文件夹,加入两个js文件
preload.js
用于隔离electron和vue的环境
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const dependency of ['chrome', 'node', 'electron']) {
replaceText(`${dependency}-version`, process.versions[dependency])
}
})
main.js
为程序的主要入口
// 控制应用生命周期和创建原生浏览器窗口的模组
const { app, BrowserWindow } = require('electron')
const path = require('path')
const NODE_ENV = process.env.NODE_ENV
function createWindow() {
// 创建浏览器窗口
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
// 通过环境加载不同的资源
mainWindow.loadURL(NODE_ENV === 'development' ? 'http://localhost:5173' : `file://${path.join(__dirname, '../dist/index.html')}`);
// 开发中打开控制台
if (NODE_ENV === 'development') {
// 打开控制台
mainWindow.webContents.openDevTools()
}
}
// 这段程序将会在 Electron 结束初始化
// 和创建浏览器窗口的时候调用
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
// 通常在 macOS 上,当点击 dock 中的应用程序图标时,如果没有其他
// 打开的窗口,那么程序会重新创建一个窗口。
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// 除了 macOS 外,当所有窗口都被关闭的时候退出程序。 因此,通常对程序和它们在
// 任务栏上的图标来说,应当保持活跃状态,直到用户使用 Cmd + Q 退出。
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
第二步:配置package.json
中的脚本,加入以下内容
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
// 加入下列内容
"electron": "wait-on tcp:5173 && cross-env NODE_ENV=development electron .",
"electron:serve": "concurrently -k \"npm run dev\" \"npm run electron\"",
"electron:preview": "vite build && electron .",
"electron:build": "vite build && electron-packager ./ my-app --platform=win32 --arch=x64 --out ./target --overwrite --icon=./favicon.ico --electron-zip-dir=D:/Bb_work/electron"
}
同时删除"type": "module"
,新增"main": "electron/main.js"
第三步:配置vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
base: "./", // 新增
plugins: [vue()],
})
此操作是让Vue打包后的资源以相对路径进行访问,否则无法加载资源
打包依赖问题
npm和cnpm有个问题是存在递归引用问题,在打包时需要一个一个安装依赖中的依赖,比较麻烦,而yarn的管理方式不存在这些问题,所以改为yarn包管理工具
npm i -g yarn
yarn --version
yarn init - 初始化新项目并创建 package.json 文件
yarn add [package] - 将一个或多个包添加到项目中
yarn remove [package] - 从项目中移除一个或多个包
yarn install - 安装项目中所有依赖项
yarn upgrade [package] - 更新一个或多个包至最新版本
yarn run [script] - 运行在 package.json 中定义的脚本
yarn build - 执行构建命令以生成生产环境所需的文件
yarn start - 启动应用程序或服务器
yarn test - 运行测试套件
安装electron一直转圈问题
// npm包管理器
npm config set ELECTRON_MIRROR https://npm.taobao.org/mirrors/electron/
yarn包管理器
yarn config set ELECTRON_MIRROR https://npm.taobao.org/mirrors/electron/
electron-packager打包忽略
electron-packager ./ desktopClient --platform=win32 --arch=x64 --out ./target --overwrite --icon=./favicon.ico --electron-zip-dir=./pack_dep --ignore=pack_dep
日志问题
如果不使用控制(生产环境没有),需要electron-log完成
yarn add electron-log
使用
const log = require('electron-log')
// 设置日志输出位置
// 设置日志文件的路径
log.transports.file.resolvePath = () => path.join(__dirname, '/logs/main.log');
// 开启控制台输出
log.transports.console.level = 'debug'
// 初始化electron-log模块
log.info('Application starting...')
// log.debug()、log.info()、log.warn()和log.error()
资源内容限制访问问题
删除index.html
的meta
,然后配置
// 创建浏览器窗口
mainWindow = new BrowserWindow({
// 完全关闭菜单栏
frame: false,
webPreferences: {
// 禁用内容安全策略
webSecurity: false,
// 开启渲染进程使用Node
nodeIntegration: true, // 控制上下文隔离
contextIsolation: false, preload: path.join(__dirname, 'preload.js'),
}
})
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
选择文件夹
// 选择文件夹
ipcMain.on('select-folder', () => {
dialog
.showOpenDialog({ properties: ['openDirectory'] })
.then((result) => {
if (!result.canceled) {
const folderPath = result.filePaths[0]
console.log('Selected folder:', folderPath)
// 返回选择的文件夹,绝对值
mainWindow.webContents.send('select-folder-back', folderPath)
}
})
.catch((err) => {
console.log(err)
})
})
允许加载本地资源
// 创建浏览器窗口
mainWindow = new BrowserWindow({
// 窗口宽度
width: 1200,
// 窗口高度
height: 800,
// 完全关闭菜单栏
frame: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
// 开启渲染进程使用Node
nodeIntegration: true,
// 关闭上下文隔离
contextIsolation: false,
// 关闭安全策略,允许加载本地资源
webSecurity: false,
},
})
PNG转ICO
https://bfotool.com/zh/png-to-ico
窗口总是置顶
// 创建浏览器窗口
mainWindow = new BrowserWindow({
// 完全关闭菜单栏
frame: false,
// 总是置顶
alwaysOnTop: true,
webPreferences: {
// 禁用内容安全策略
webSecurity: false,
// 开启渲染进程使用Node
nodeIntegration: true,
// 控制上下文隔离
contextIsolation: false,
preload: path.join(__dirname, 'preload.js'),
},
})
开启透明
app.on("ready", () => {
let mainWindow = new BrowserWindow({
width: 1200,
height: 800,
transparent: true, // 开启透明
frame: false, // 去掉窗口边框,透明才会生效
});
// 加载本地资源
mainWindow.loadFile("index.html");
});
加flash插件
https://newsn.net/say/electron-flash-win.html
https://www.flash.cn/download-wins