electron+vue开发·
1、搭建项目
1.1、vue cli + electron-builder安装方法1.1.1、创建vue项目
```vue create electron-demo```
1.1.2、安装electron-builder插件·
vue add electron-builder
1.2、vue cli + vue-cli-plugin-electron-builder安装方法 1.1.1、创建vue项目
vue create electron-demo
1.1.2、安装vue-cli-plugin-electron-builde插件
vue add vue-cli-plugin-electron-builde
2、窗口配置
例如登录窗口config.ts
login: {
url: `${baseUrl}#/login`,
hideReplaceClose: false,
name: 'login',
setup: {
width: 340,
height: 450,
...commonWindowConfig
}
}
具体窗口配置内容
import { BrowserWindowConstructorOptions } from 'electron'
import { closeWindow, showWindow, hideWindow } from '@/main/methods'
const baseUrl = process.env.WEBPACK_DEV_SERVER_URL ? process.env.WEBPACK_DEV_SERVER_URL : `file://${__dirname}/index.html`
const platform = process.platform
const windowMap = new Map()
const commonWindowConfig: BrowserWindowConstructorOptions = {
show: false,
frame: false,
maximizable: false,
fullscreenable: false,
resizable: false,
useContentSize: false,
center: true,
titleBarStyle: 'hidden',
webPreferences: {
nodeIntegration: true,
webSecurity: false,
devTools: true,
enableRemoteModule: true
}
}
const windowConfig = {
login: {
url: `${baseUrl}#/login`,
hideReplaceClose: false,
name: 'login',
setup: {
width: 340,
height: 450,
...commonWindowConfig
}
},
home: {
url: `${baseUrl}`,
hideReplaceClose: true,
name: 'home',
setup: {
width: 700,
height: 588,
...commonWindowConfig
},
onCreated: function () {
closeWindow(['login'])
},
onClosed: function () {
closeWindow(['create', 'edit'])
}
},
create: {
url: `${baseUrl}#/create`,
name: 'create',
setup: {
width: 499,
height: 688,
...commonWindowConfig
}
},
edit: {
url: `${baseUrl}#/create`,
name: 'edit',
setup: {
width: 499,
height: 688,
...commonWindowConfig
}
},
room: {
url: `${baseUrl}#/live-room`,
name: 'room',
setup: {
width: 1300,
height: 692,
minWidth: 1166,
minHeight: 650,
...commonWindowConfig,
fullscreenable: true,
maximizable: true,
resizable: true,
useContentSize: false
},
onCreated: function () {
closeWindow(['create', 'edit', 'home', 'login'])
},
onClosed: function () {}
}
}
export {
baseUrl,
platform,
windowMap,
windowConfig
}
3、创建窗口配置,methods.ts
import { windowMap, windowConfig, platform } from '@/main/config'
import { CreateWindowConfig } from '@/main/types'
import { BrowserWindow, BrowserWindowConstructorOptions } from 'electron'
import { handleContextMenu } from '@/main/menu'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
export function createWindow (options: CreateWindowConfig, onComplete?: () => void): BrowserWindow {
const config: BrowserWindowConstructorOptions = JSON.parse(JSON.stringify(options.setup))
// webSecurity: 展示上传文件的照片路径问题
// nodeIntegration 解决报window.require
// enableRemoteModule 解决报 Cannot destructure property 'dialog' of 'require(...).remote' as it is undefined
config.webPreferences = {
nodeIntegration: true,
enableRemoteModule: true,
contextIsolation: false,
webSecurity: false
}
if (platform !== 'darwin' && config.height) {
config.height = config.height + 8
}
const win = new BrowserWindow(config)
windowMap.set(options.name, win.id)
if (typeof options.onCreated === 'function') {
try {
options.onCreated(win)
} catch (e) {
console.log(e)
}
}
win.on('show', () => {
win.webContents.send('window-show')
})
win.on('focus', () => {
win.webContents.send('window-focus')
})
win.on('maximize', () => {
win.webContents.send('maximize')
})
win.on('unmaximize', () => {
win.webContents.send('unmaximize')
})
win.on('closed', () => {
windowMap.delete(options.name)
if (typeof options.onClosed === 'function') {
options.onClosed()
}
})
win.on('ready-to-show', () => {
win.show()
})
win.loadURL(options.url).then(() => {
win.webContents.on('context-menu', handleContextMenu)
})
if (onComplete) {
onComplete()
}
return win
}
export function findBrowserWindow (name: string): BrowserWindow | null {
const windowId = windowMap.get(name)
if (!windowId) return null
return BrowserWindow.fromId(windowId)
}
// 接受 BrowserWindow 的 name 数组或者 id
export function closeWindow (windowNameList: string[] | number): void {
if (typeof windowNameList === 'number') {
const window = BrowserWindow.fromId(windowNameList)
window && window.isClosable() && window.close()
return
}
windowNameList.forEach(name => {
const window = findBrowserWindow(name)
if (!window) return
window.isClosable() && window.close()
})
}
export function hideWindow (name: string): void {
const win = findBrowserWindow(name)
if (!win) return
win.hide()
}
export function showWindow (name: string): void {
const win = findBrowserWindow(name)
if (!win) return
win.show()
}
export function startApp (): void {
const loginWindow = findBrowserWindow('login')
if (!loginWindow) {
createWindow(windowConfig.login)
} else {
loginWindow.show()
}
if (!process.env.WEBPACK_DEV_SERVER_URL) {
createProtocol('app')
}
}
export function handleAppActive (): void {
const currentWindow = BrowserWindow.getFocusedWindow()
if (currentWindow !== null) {
return currentWindow.show()
}
const roomWindow = findBrowserWindow('room')
if (roomWindow !== null) {
return roomWindow.show()
}
const allWindows = BrowserWindow.getAllWindows()
if (allWindows.length > 0) {
const lastWindow = allWindows.pop()
lastWindow && lastWindow.show()
} else {
const loginWindow = findBrowserWindow('login')
if (!loginWindow) {
createWindow(windowConfig.login)
} else {
loginWindow.show()
}
}
}
4、窗口通讯
窗口通讯逻辑electron窗口之间的通讯是由窗口=》主线程=》B窗口这样的逻辑,例如A窗口向主线程发起通讯,然后主线程根据A窗口发送的要求寻找需它需要的发送信息的页面进行发送信息
A窗口向home窗口发送一个方法名为‘methodsName’的信息,参数名称是xx
const { ipcRender } = window.require(‘electron’)
ipcRender.send(‘methodsName’, { name: ‘home’, xx: xxx})
主线程 listener.ts
const { ipcMain , IpcMessageEvent } = window.require(‘electron’)
import{ findBrowserWindow } from ‘methods’// 前面编写的ts
ipcMain.on(‘methodsName’, (e: IpcMessageEvent , data: {xxx})) => {
// 查找窗口
const win: any = findBrowserWindow (data.name)
if (win && win.webContents) {
win.webContents.send(‘methodsName’, data.xx)
}
})
B窗口
const { ipcRender } = window.require(‘electron’)
ipcRender.on(‘methodsName’, (e: any, args: any) = { console.log(args.xx)})
5、程序添加权限
Vue.config.js 内容配置
module.exports = {
chainWebpack: config => {
// svg rule loader
const svgRule = config.module.rule('svg') // 找到svg-loader
svgRule.uses.clear() // 清除已有的loader, 如果不这样做会添加在此loader之后
svgRule.exclude.add(/node_modules/) // 正则匹配排除node_modules目录
// svgRule.oneOfs.clear()
svgRule // 添加svg新的loader处理
.test(/\.svg$/)
.use('raw-loader')
.loader('raw-loader')
},
devServer: {
host: '0.0.0.0',
port: 6060
},
pages: {
index: {
entry: 'src/main.ts',
template: 'public/index.html',
filename: 'index.html',
title: '测试'
}
},
pluginOptions: {
electronBuilder: {
// node_modules,打包的时候需要的
externals: [''],
// node_modules,打包的时候需要的资源,不能打包压缩
extraResources: [
'./node_modules/xxx/**',
],
// 监听主程序
mainProcessWatch: ['src/background.ts', 'src/main/*', 'src/main/config.ts', 'src/main/method.ts'],
// If you are using Yarn Workspaces, you may have multiple node_modules folders
// List them all here so that VCP Electron Builder can find them
nodeModulesPath: ['./node_modules'],
builderOptions: {
productName: '程序名字随便起',
copyright: '版权',
appId: '开发id',
extraResources: [
'./build/xxx-logs/**'
],
dmg: {
sign: false,
// eslint-disable-next-line no-template-curly-in-string
title: '${productName} ${version}',
contents: [
{
x: 410,
y: 150,
type: 'link',
path: '/Applications'
},
{
x: 130,
y: 150,
type: 'file'
}
]
},
mac: {
category: 'public.app-category.productivity',
target: 'dmg',
hardenedRuntime: true,
gatekeeperAssess: false,
// 权限列表
entitlements: 'build/entitlements.mac.plist',
entitlementsInherit: 'build/entitlements.mac.plist',
// 应用图标
icon: 'build/icons/icon.icns'
},
win: {
target: [
{
target: 'nsis', // 利用nsis制作安装程序
arch: ['x64']
// 64位应用
}
],
// 应用图标
icon: 'build/icons/icon.ico'
},
nsis: {
differentialPackage: false,
perMachine: false,
oneClick: false, // 是否一键安装
allowElevation: true, // 允许请求提升。若为false,则用户必须使用提升的权限重新启动安装程序。
allowToChangeInstallationDirectory: true, //是否允许修改安装目录
installerIcon: 'build/icons/icon.ico', // 安装时图标
uninstallerIcon: 'build/icons/icon.ico', // 卸载时图标
installerHeaderIcon: 'build/icons/icon.ico', // 安装时头部图标
createDesktopShortcut: true, // 是否创建桌面图标
createStartMenuShortcut: true, // 是否创建开始菜单图标
deleteAppDataOnUninstall: true,
include: 'build/installer.nsh'
}
}
}
}
}
其中mac权限申请列表
entitlements.mac.list
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.device.camera</key>
<true/>
</dict>
</plist>
Installer.nsh配置文件需要根据项目需要配置