首頁>技術>

今天給大家分享一些Vue3整合Electron新建多開視窗的相關知識。

至於如何搭建vue3+electron專案,大家可以去看看之前的這篇分享文章。

一般建立多開視窗思路都是需要新建就會建立一個new BrowserWindow({...}),一個兩個還行,但是當需要建立多個窗體,比如QQ,這樣操作就顯得太low。

這時候如果能封裝成一個函式,每一次新建就傳入相應引數,這樣就簡便多了~~ 類似如下程式碼片段。

windowCreate({      title: '使用者中心',      route: '/ucenter',      width: 750,      height: 500,      backgroundColor: '#f9f9f9',      resizable: false,      maximize: true,      modal: true,})

vue3+electron整合的專案,根目錄會有一個background.js主入口檔案。

'use strict'import { app, BrowserWindow } from 'electron'const isDevelopment = process.env.NODE_ENV !== 'production'import { Window } from './windows'async function createWindow() {  let window = new Window()    window.listen()  window.createWindows({isMainWin: true})  window.createTray()}app.on('window-all-closed', () => {  if (process.platform !== 'darwin') {    app.quit()  }})app.on('activate', () => {  if (BrowserWindow.getAllWindows().length === 0) createWindow()})app.on('ready', async () => {  createWindow()})if (isDevelopment) {  if (process.platform === 'win32') {    process.on('message', (data) => {      if (data === 'graceful-exit') {        app.quit()      }    })  } else {    process.on('SIGTERM', () => {      app.quit()    })  }}

然後新建一個windows.js,用來處理主程序相關函式。

import { app, BrowserWindow, ipcMain, Menu, Tray } from "electron";import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'import path from 'path'export const windowsCfg = {    id: '', //唯一id    title: '', //視窗標題    width: '', //寬度    height: '', //高度    minWidth: '', //最小寬度    minHeight: '', //最小高度    route: '', // 頁面路由URL    resizable: true, //是否支援調整視窗大小    maximize: false, //是否最大化    backgroundColor:'#eee', //視窗背景色    data: null, //資料    isMultiWindow: false, //是否支援多開視窗    isMainWin: false, //是否主視窗    parentId: '', //父視窗id  建立父子視窗    modal: false, //模態視窗}/** * 視窗配置 */export class Window {    constructor() {        this.main = null; //當前頁        this.group = {}; //視窗組        this.tray = null; //托盤    }    // 視窗配置    winOpts(wh=[]) {        return {            width: wh[0],            height: wh[1],            backgroundColor: '#f00',            autoHideMenuBar: true,            titleBarStyle: "hidden",            resizable: true,            minimizable: true,            maximizable: true,            frame: false,            show: false,            webPreferences: {                contextIsolation: false, //上下文隔離                // nodeIntegration: true, //啟用Node整合(是否完整的支援 node)                nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,                // devTools: false,                webSecurity: false,                enableRemoteModule: true, //是否啟用遠端模組(即在渲染程序頁面使用remote)            }        }    }    // 獲取視窗    getWindow(id) {        return BrowserWindow.fromId(id)    }    // 獲取全部視窗    getAllWindows() {        return BrowserWindow.getAllWindows()    }    // 建立視窗    createWindows(options) {        console.log('------------開始建立視窗...')        console.log(options)        let args = Object.assign({}, windowsCfg, options)        console.log(args)        // 判斷視窗是否存在        for(let i in this.group) {            if(this.getWindow(Number(i)) && this.group[i].route === args.route && !this.group[i].isMultiWindow) {                this.getWindow(Number(i)).focus()                return            }        }        let opt = this.winOpts([args.width || 800, args.height || 600])        if(args.parentId) {            console.log('parentId:' + args.parentId)            opt.parent = this.getWindow(args.parentId)        } else if(this.main) {            console.log(666)        }        if(typeof args.modal === 'boolean') opt.modal = args.modal        if(typeof args.resizable === 'boolean') opt.resizable = args.resizable        if(args.backgroundColor) opt.backgroundColor = args.backgroundColor        if(args.minWidth) opt.minWidth = args.minWidth        if(args.minHeight) opt.minHeight = args.minHeight        console.log(opt)        let win = new BrowserWindow(opt)        console.log('視窗id:' + win.id)        this.group[win.id] = {            route: args.route,            isMultiWindow: args.isMultiWindow,        }        // 是否最大化        if(args.maximize && args.resizable) {            win.maximize()        }        // 是否主視窗        if(args.isMainWin) {            if(this.main) {                console.log('主視窗存在')                delete this.group[this.main.id]                this.main.close()            }            this.main = win        }        args.id = win.id        win.on('close', () => win.setOpacity(0))        // 開啟網址(載入頁面)        /**         * 開發環境: http://localhost:8080         * 正式環境: app://./index.html         */        let winURL        if (process.env.WEBPACK_DEV_SERVER_URL) {            // Load the url of the dev server if in development mode            // win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)            winURL = args.route ? `http://localhost:8080${args.route}` : `http://localhost:8080`            // 開啟開發者除錯工具            // if (!process.env.IS_TEST) win.webContents.openDevTools()        } else {            createProtocol('app')            // Load the index.html when not in development            // win.loadURL('app://./index.html')            winURL = args.route ? `app://./index.html${args.route}` : `app://./index.html`        }        win.loadURL(winURL)        win.once('ready-to-show', () => {            win.show()        })        // 遮蔽視窗選單(-webkit-app-region: drag)        win.hookWindowMessage(278, function(e){            win.setEnabled(false)            setTimeout(() => {                win.setEnabled(true)            }, 100)            return true        })    }    // 關閉所有視窗    closeAllWindow() {        for(let i in this.group) {            if(this.group[i]) {                if(this.getWindow(Number(i))) {                    this.getWindow(Number(i)).close()                } else {                    console.log('---------------------------')                    app.quit()                }            }        }    }    // 建立托盤    createTray() {        console.log('建立托盤')        const contextMenu = Menu.buildFromTemplate([            {                label: '顯示',                click: () => {                    for(let i in this.group) {                        if(this.group[i]) {                            // this.getWindow(Number(i)).show()                            let win = this.getWindow(Number(i))                            if(!win) return                            if(win.isMinimized()) win.restore()                            win.show()                        }                    }                }            }, {                label: '退出',                click: () => {                    app.quit()                }            }        ])        console.log(__dirname)        const trayIco = path.join(__dirname, '../static/logo.png')        console.log(trayIco)        this.tray = new Tray(trayIco)        this.tray.setContextMenu(contextMenu)        this.tray.setToolTip(app.name)    }    // 開啟監聽    listen() {        // 關閉        ipcMain.on('window-closed', (event, winId) => {            if(winId) {                this.getWindow(Number(winId)).close()                if(this.group[Number(winId)]) delete this.group[Number(winId)]            } else {                this.closeAllWindow()            }        })        // 隱藏        ipcMain.on('window-hide', (event, winId) => {            if(winId) {                this.getWindow(Number(winId)).hide()            } else {                for(let i in this.group) if(this.group[i]) this.getWindow(Number(i)).hide()            }        })        // 顯示        ipcMain.on('window-show', (event, winId) => {            if(winId) {                this.getWindow(Number(winId)).show()            } else {                for(let i in this.group) if(this.group[i]) this.getWindow(Number(i)).show()            }        })        // 最小化        ipcMain.on('window-mini', (event, winId) => {            if(winId) {                this.getWindow(Number(winId)).minimize()            } else {                for(let i in this.group) if(this.group[i]) this.getWindow(Number(i)).minimize()            }        })        // 最大化        ipcMain.on('window-max', (event, winId) => {            if(winId) {                this.getWindow(Number(winId)).maximize()            } else {                for(let i in this.group) if(this.group[i]) this.getWindow(Number(i)).maximize()            }        })        // 最大化/最小化        ipcMain.on('window-max-min-size', (event, winId) => {            if(winId) {                if(this.getWindow(winId).isMaximized()) {                    this.getWindow(winId).unmaximize()                }else {                    this.getWindow(winId).maximize()                }            }        })        // 還原        ipcMain.on('window-restore', (event, winId) => {            if(winId) {                this.getWindow(Number(winId)).restore()            } else {                for(let i in this.group) if(this.group[i]) this.getWindow(Number(i)).restore()            }        })        // 重新載入        ipcMain.on('window-reload', (event, winId) => {            if(winId) {                this.getWindow(Number(winId)).reload()            } else {                for(let i in this.group) if(this.group[i]) this.getWindow(Number(i)).reload()            }        })        // 建立視窗        ipcMain.on('window-new', (event, args) => this.createWindows(args))    }}

新建plugin.js,用來封裝一些呼叫方法。

/** * 新建視窗 */export function windowCreate(args) {    console.log(args)    ipcRenderer.send('window-new', args)}/** * 關閉視窗 */export function windowClose(id) {    console.log('視窗id:' + id)    ipcRenderer.send('window-closed', id)}// ...

在渲染程序.vue頁面,呼叫plugin.js裡面的函式。

<template>    <div class="app">        <img src="@assets/v3-logo.png" />        <a-button type="primary" @click="handleWin1">新視窗1</a-button>        <a-button type="primary" @click="handleWin2">新視窗2</a-button>    </div></template><script>import {windowClose, windowCreate} from '@/plugins'export default {    setup() {        const handleWin1 = () => {            windowCreate({                title: '我的頁面',                route: '/me',                width: 1200,                height: 750,                backgroundColor: '#f9f9f9',                resizable: true,                modal: true,                maximize: true,            })        }                const handleWin2 = () => {            windowCreate({                title: '新聞頁面',                route: '/news?id=20210215',                width: 960,                height: 550,                backgroundColor: '#f90',                resizable: false,            })        }                ...        return {            handleWin1,            handleWin2,            ...        }    }}</script>

這樣就實現了透過封裝函式來呼叫新建視窗了。

在開發過程中遇到的一些問題/踩坑。

托盤圖示載入本地圖片失敗?

一開始一直以為__dirname指向src目錄,後來經過除錯,原來是指向了dist_electron目錄。

console.log(__dirname)let trayIco = path.join(__dirname, '../static/logo.png')console.log(trayIco)

這樣就能正確獲取到本地圖片了。

後來經過一番倒騰,可以透過下面這段程式碼來禁用掉右鍵選單。

好了,以上基於一些vue3結合electron建立多個窗體的一些分享。

11
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • vue自定義元件——>圖示選擇元件