electron+vue开发

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配置文件需要根据项目需要配置

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容