项目安装
Electron-vue其实就是一个脚手架模板,类似于大家用的vue-cli
vue init simulatedgreg/electron-vue my-project
项目目录
进程通讯
Electron其实就两个主要的进程,一个主进程(负责桌面应用原生的操作);一个渲染进程(负责页面展示)。
渲染进程向主进程发送消息
// vue 页面中
// 引入通讯模块
import { ipcRenderer } from 'electron'
let msg = '哈哈哈哈'
// 向主进程发送消息
ipcRenderer.send('my-renderer-message', msg)
注:主进程的中运行的都是node.js,所以console都会出现在控制台
// main/index.js
// 引入通讯模块
import { ipcMain } from 'electron'
// 接收渲染进程的消息
ipcMain.on('my-renderer-message', (e, msg) => {
console.log(e, msg)
// do someing
})
主进程向渲染进程发送消息
// main/index.js
// 实例化窗口
let mainWindow = new BrowserWindow({
height: 563,
useContentSize: true,
width: 1000
})
// 向渲染进程发送消息
mainWindow.webContents.send('my-main-message')
// vue 页面中
// 引入通讯模块
import { ipcRenderer } from 'electron'
// 接收主进程消息
ipcRenderer.on('my-main-message', () => {
// do someing
})
生命周期
窗口相关
首先会走ready,然后在里面实例化BrowserWindow。并在后面添加了一些相关的监听
注:app.on和mainWindow.on的区别,所有的mainWindow.on必须在BrowserWindow实例化后
// main/index.js
import { app, BrowserWindow} from 'electron'
let mainWindow
app.on('ready', ()=>{
console.log('---ready----')
mainWindow = new BrowserWindow({
height: 563,
useContentSize: true,
width: 1000
})
// 此处的winURL就是渲染进程的入口
let winURL = 'http://localhost:9080'
mainWindow.loadURL(winURL)
// 窗口变化时触发
mainWindow.on('resize', (event) => {
console.log('---mainWindow-resize----')
})
// 窗口最大化时触发
mainWindow.on('maximize', (event) => {
console.log('---mainWindow-maximize----')
})
// 窗口关闭时触发
mainWindow.on('close', (event) => {
console.log('---mainWindow-close----')
})
// 窗口已经关闭
mainWindow.on('closed', () => {
console.log('---mainWindow-closed----')
mainWindow = null
})
})
// 应用如果没退出,只是进入后台了,再次启动时会触发activate
app.on('activate', () => {
console.log('---activate----')
if (mainWindow === null) {
createWindow()
}
})
app.on('window-all-closed', () => {
console.log('---window-all-closed----')
})
// 调用 event.preventDefault(),可阻止默认行为
app.on('will-quit', () => {
console.log('---will-quit----')
})
// 调用 event.preventDefault(),可阻止默认行为
app.on('before-quit', () => {
console.log('---before-quit----')
})
app.on('quit', () => {
console.log('---quit----')
})
点击应用的关闭按钮
1.如果所有的监听里面都不写app.quit()或app.exit(),打印顺序如下。且进程不会被关闭
---mainWindow-close----
---window-all-closed----
---mainWindow-closed----
2.如果app.quit()写在close中,打印顺序如下。进程会被关闭
---mainWindow-close----
---before-quit----
---mainWindow-close----
---will-quit----
---quit----
---mainWindow-closed----
3.如果app.quit()写在window-all-closed中,打印顺序如下。进程会被关闭
---mainWindow-close----
---window-all-closed----
---before-quit----
---will-quit----
---quit----
---mainWindow-closed----
4.如果app.quit()写在before-quit;will-quit;quit中。效果和第一条一样 5.如果app.quit()写在closed中。打印顺序如下。进程会被关闭
---mainWindow-close----
---window-all-closed----
---mainWindow-closed----
---before-quit----
---will-quit----
---quit----
6.如果使用app.exit(),会在app.exit() 之后打印会直接跳到quit。关闭进程
---mainWindow-close----
// app.exit() 之后会直接到quit并关闭进程
---quit----
结合上面的生命周期做拦截应用的叉叉,做退出确认
大体思路是在主进程的close中,向渲染层发送消息,并阻止默认操作。渲染层收到消息后弹框确认,向主进程发送消息,主进程执行app.exit()。不用app.quit()的原因,是因为app.quit()会再次出发close,流程上会形成死循环。
// main/index.js
// 引入模块
import { app, BrowserWindow, ipcMain } from 'electron'
let mainWindow
app.on('ready', ()=>{
console.log('---ready----')
mainWindow = new BrowserWindow({
height: 563,
useContentSize: true,
width: 1000
})
// 此处的winURL就是渲染进程的入口
let winURL = 'http://localhost:9080'
mainWindow.loadURL(winURL)
// 窗口关闭时触发
mainWindow.on('close', (event) => {
console.log('---mainWindow-close----')
// 通知渲染进程,用户点击了关闭应用
mainWindow.webContents.send('master-closed')
// 拦截默认操作
event.preventDefault()
})
})
// 监听从渲染进程发过来的消息,并执行退出
ipcMain.on('master-close-app', () => {
console.log('master-close-app')
app.exit()
})
// vue页面中
import { ipcRenderer } from 'electron'
mounted () {
// 监听主进程发过来的消息,并打开弹框
ipcRenderer.on('master-closed', () => {
this.dialogShow = true
})
},
methods: {
// 点击确认关闭,并通知主进程操作
doConfirm () {
ipcRenderer.send('master-close-app')
},
}
其他监听或方法,请参考官方文档
打包相关
如果是是直接使用脚手架生成的项目,都已经安装了electron-builder,直接build出来的是免安装的应用。如果需自定义,配置如下
基础配置
// package.json 文件中
"win": {
"icon": "build/icons/icon.ico",
"target": [
{
"target": "nsis" // 此处可以为数组,同时打出几个类型的包:["nsis","zip","mis"]
}
]
},
"nsis": {
"oneClick": false, // 是否一键安装,建议为 false,可以让用户点击下一步、下一步、下一步的形式安装程序,如果为true,当用户双击构建好的程序,自动安装程序并打开,即:一键安装(one-click installer)
"allowElevation": true, // 允许请求提升。 如果为false,则用户必须使用提升的权限重新启动安装程序。
"allowToChangeInstallationDirectory": true, // 允许修改安装目录,建议为 true,是否允许用户改变安装目录,默认是不允许
"installerIcon": "", // 安装图标
"uninstallerIcon": "", // 卸载图标
"installerHeaderIcon": "", // 安装时头部图标
"createDesktopShortcut": true, // 创建桌面图标
"createStartMenuShortcut": true, // 创建开始菜单图标
"shortcutName": "xxxx", // 快捷方式名字
"include": "installer.nsh" // 自定义的安装脚本(如没有自定义脚本,不需写该行)
}
自定义安装目录脚本
//installer.nsh 文件中
!macro preInit
SetRegView 64
WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "D:\haha"
WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "D:\haha"
SetRegView 32
WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "D:\haha"
WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "D:\haha"
!macroend
使用NSIS软件
其他
运行时窗口左上角图标配置
实例化窗口时添加icon,代码如下
// main/index.js 文件中
if (process.env.NODE_ENV !== 'development') {
global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
}
mainWindow = new BrowserWindow({
icon: __static + '/icon.icon', // 开发环境不需要__static
height: 563,
autoHideMenuBar: true,
useContentSize: true,
width: 1000
})