当前位置 博文首页 > xiaoyan2017:基于vue3.0+electron新开窗口|Electron多开窗体|父

    xiaoyan2017:基于vue3.0+electron新开窗口|Electron多开窗体|父

    作者:xiaoyan2017 时间:2021-02-15 16:31

    最近一直在折腾Vue3+Electron技术结合的实践,今天就来分享一些vue3.x和electron实现开启多窗口功能。

    开始本文之前,先来介绍下如何使用vue3和electron来快速搭建项目。

    目前electron.js的star高达89.3K+,最新稳定版v11.2.3

    使用vue开发electron应用,网上有个比较火的脚手架electron-vue,不过里面的版本太低,而且使用的是vue2.x语法。

    今天主要分享的是vue3语法开发electron应用,所以只能手动搭建开发环境。

    • 安装最新Vue CLI脚手架。

     npm install -g @vue/cli 

    • 新建vue3项目

    具体的选项配置,大家根据需要勾选。

     vue create vue3_electron 

    • vue3项目中集成electron

    安装vue-cli-plugin-electron-builder插件。

     cd vue3_electron  vue add electron-builder 

    之后的安装过程中会提示安装electron版本,选择最新版安装就行。

    • 开发调试/打包构建

     npm run electron:serve  npm run electron:build 

    非常简单,没有几步就能快速手动搭建vue3+electron项目,下面就能愉快的开发了。

    一般项目中需要新建多开窗口的功能,使用Electron来创建也是非常简单的。一般的实现方法是  new BrowserWindow({...})  窗口,传入参数配置即可快速新建一个窗口。

    <body>
        <button id="aaa">打开A窗口</button>
        <button id="bbb">打开B窗口</button>
        <button id="ccc">打开C窗口</button>
    </body>
    
    <script>
        import path from 'path'
        import { remote } from 'electron'
        
        let BrowserWindow = remote.BrowserWindow;
        
        let winA = null;
        let winB = null;
        let winC = null;
        
        document.getElementById("aaa").onclick = function(){
            winA = new BrowserWindow ({width: 1000, height:800})
            winA.loadURL("https://aaa.com/");
            winA.on("close", function(){
                winA = null;
            })
        }
        
        document.getElementById("bbb").onclick = function(){
            winB = new BrowserWindow ({width: 900, height:650})
            winB.loadURL("https://bbb.com/");
            winB.on("close", function(){
                winB = null;
            })
        }
        
        document.getElementById("ccc").onclick = function(){
            winC = new BrowserWindow ({width: 500, height:500})
            winC.loadURL(`file://${__dirname}/news.html`);
            winC.on("close", function(){
                winC = null;
            })
        }
    </script>

    具体的参数配置,大家可以去查阅文档,electron官网中都有非常详细的说明。

    https://www.electronjs.org/docs/api/browser-window

    但是这种方法每次都要新建一个BrowserWindow,有些挺麻烦的,能不能像下面代码片段这样,直接通过一个函数,然后传入配置参数生成新窗口,显然是可以的。

    windowCreate({
          title: '管理页面',
          route: '/manage?id=123',
          width: 750,
          height: 500,
          backgroundColor: '#f9f9f9',
          resizable: false,
          maximize: true,
          modal: true,
    })

    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()
        })
      }
    }

    新建一个 window.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 '/manage?id=123'
        resizable: true, //是否支持调整窗口大小
        maximize: false, //是否最大化
        backgroundColor:'#eee', //窗口背景色
        data: null, //数据
        isMultiWindow: false, //是否支持多开窗口 (如果为false,当窗体存在,再次创建不会新建一个窗体 只focus显示即可,,如果为true,即使窗体存在,也可以新建一个)
        isMainWin: false, //是否主窗口(当为true时会替代当前主窗口)
        parentId: '', //父窗口id  创建父子窗口 -- 子窗口永远显示在父窗口顶部 【父窗口可以操作】
        modal: false, //模态窗口 -- 模态窗口是禁用父窗口的子窗口,创建模态窗口必须设置 parent 和 modal 选项 【父窗口不能操作】
    }
    
    /**
     * 窗口配置
     */
    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`
    
    下一篇:没有了