目录 一、前言 二、实施方案 1.创建多窗口 2.多窗口间的通信 三、后记 一、前言 对于一个桌面应用来说,有时候单独一个窗口用户使用起来会不太方便,比方说写日报或者查看文件等
目录
- 一、前言
- 二、实施方案
- 1.创建多窗口
- 2.多窗口间的通信
- 三、后记
一、前言
对于一个桌面应用来说,有时候单独一个窗口用户使用起来会不太方便,比方说写日报或者查看文件等,若是在同一窗口内,我只能做一件事,不能边预览文件,边去查看聊天消息内容等。又或者是多个应用间相互关联的需要同步查看的事件,这都是极其不方便的。因此我们可以将某些集成到electron软件中的应用或者某些界面用单独的窗口打开(以下称为独立窗口)。
二、实施方案
1.创建多窗口
首先我们从electron官网中找到创建窗口的方法,electron官网的BrowserWindow,接下来我们就简单写一个独立窗口的创建。这个窗口可以打开外部应用也可以是应用内部。
// windows/CreateIndependentWindow.js import { BrowserWindow, globalShortcut, ipcMain } from 'electron' import { createProtocol } from 'vue-cli-plugin-electron-builder/lib' // 关于这个插件,可以看下前几天我写的解决electron白屏那篇文章 import CreateProcessLoadingPage from './CreateProcessLoadingPage' /** * 必传参数 * outUrl 外部链接 * or * inUrl 内部链接 * windowTitle 页面标题 注意:此值不可重复 */ const CreateIndependentWindow = ({ ...data }, win) => { const obj = { // 窗口的大小可以通过传进来的参数控制 height: data.height || 640, width: data.width || 1024, show: false, // 初始是否可显示 center: true, // 窗口是否可以进入全屏状态 fullscreenable: false, closable: true, // 窗口是否可关闭 resizable: true, // 禁止改变主窗口尺寸 webPreferences: { nodeIntegration: true, // 启用Node integration webSecurity: false, webviewTag: true, // 允许在页面内使用webview标签 enableRemoteModule: true, // 允许渲染进程使用remote模块 nodeIntegrationInWorker: true, // 在Web工作器中启用了Node集成 // 允许在子页面(iframe)或子窗口(child window)中集成Node.js nodeIntegrationInSubFrames: true } } // 这里创建窗口实例 const independentWindow = new BrowserWindow(obj) // 注册全局快捷键-打开开发者工具(方便查看问题) globalShortcut.register('CommandOrControl+alt+shift+l', () => { independentWindow.webContents.openDevTools() }) // 设置窗口名称 independentWindow.setTitle(data.windowTitle || '人脉旺') // 这里将当前窗口的唯一id,存入全局变量,以容易区分多个独立窗口 // 变量声明下方说明 global.sharedObject.independentWindow.set(data.windowTitle, independentWindow.webContents.id) // 声明打开页面的url let winURL = '' // /IndependentWindow这个路由是在渲染进程创建的承载外部链接的独立窗口的页面 if (process.env.WEBPACK_DEV_SERVER_URL) { // 判断若为开发环境 // independentWindow.webContents.openDevTools() winURL = process.env.WEBPACK_DEV_SERVER_URL + '#/' + (data.inUrl ? data.inUrl : 'IndependentWindow') } else { createProtocol('app') winURL = 'app://./index.html#' + (data.inUrl ? data.inUrl : '#/IndependentWindow') } // 这里是为了获取拼接需要传入到页面的参数 const param = Object.keys(data).reduce((pre, cue) => { return data[cue] ? `${pre}${pre === '?' ? '' : '&'}${cue}=${data[cue]}` : pre }, '?') // 使用loadURL方法将页面注入到窗口 independentWindow.loadURL(winURL + param) // 若参数设置开启最大化窗口 if (data.maxSize) { independentWindow.maximize() } // 加载页面loading CreateProcessLoadingPage(independentWindow, data) independentWindow.on('close', (e) => { globalShortcut.unregister('CommandOrControl+alt+shift+l') global.sharedObject.independentWindow.delete(data.windowTitle) setTimeout(() => { if (!independentWindow.isDestroyed() && independentWindow) { independentWindow.destroy() } }, 100) }) global['independentWindow-' + independentWindow.webContents.id] = independentWindow } export default CreateIndependentWindow
之后我们在主进程中做一个监听,用来创建独立窗口
ipcMain.on('createOtherWindow', (e, data) => { // type窗口类型,data 参数 const name = data.windowTitle // 判断当前窗口是否已经存在, 存在的话 直接唤起 if (global.sharedObject.independentWindow.has(name)) { const id = global.sharedObject.independentWindow.get(name) global['independentWindow-' + id].show() } else { CreateIndependentWindow(data, win) } })
这里我们记得声明一下存储独立窗口id的变量
// background.js // 多窗口数据存储 global.sharedObject = { independentWindow: new Map(), }
之后我们在渲染进程创建一个页面,用来展示外部链接页面
<template> <div class="independent-window"> <webview id="myWebView" :src="outUrl" style="display:inline-flex; width:100%; height:100%" allowpopups></webview> </div> </template> <script> export default { name: 'IndependentWindow', data () { return { outUrl: '', } }, created () { this.outUrl = this.$route.query.outUrl }, mounted () { this.eventHandler() }, methods: { // 监听打开webview控制台的快捷键 eventHandler () { const webview = document.querySelector('#myWebView') // 用于查看webview内第三方应用问题,快捷键打开webview的开发者工具 window.addEventListener('keydown', e => { if (e.altKey && e.ctrlKey && e.shiftKey && e.keyCode === 190) { webview.openDevTools() } }) } } } </script> <style lang="less" scoped> .independent-window { width: 100%; height: 100%; } </style>
综上,我们就创建了一个独立窗口,这个独立窗口可以打开项目内页面又或者第三方外部链接窗口。
2.多窗口间的通信
electron官方文档给我们提供了关于多个窗口间通讯的方法, 对于多窗口间的通讯,多是指渲染进程间的通讯。 这里我们可以使用ipcRenderer.sendTo()这个方法,来进行多窗口建的通信。详见官方文档说明
ipcRenderer.sendTo(webContentsId, channel, ...args)
以下是官方文档内容
webContentsId
numberchannel
string...args
any[]
通过 channel
发送消息到带有 webContentsId
的窗口.
这里就用到了我们之前在global.sharedObject.independentWindow
中存储的各个窗口的id。 划重点一定是窗口实例的webContentsId
的id,而不是窗口的id,别问我怎么知道的,问也不说