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.2.1、创建vue项目
```
vue create electron-demo
````
#### 1.2.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
        }
    },
    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配置文件需要根据项目需要配置

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容