vue+electron實(shí)現(xiàn)創(chuàng)建多窗口及窗口間的通信(實(shí)施方案)
一、前言
對(duì)于一個(gè)桌面應(yīng)用來(lái)說(shuō),有時(shí)候單獨(dú)一個(gè)窗口用戶使用起來(lái)會(huì)不太方便,比方說(shuō)寫(xiě)日?qǐng)?bào)或者查看文件等,若是在同一窗口內(nèi),我只能做一件事,不能邊預(yù)覽文件,邊去查看聊天消息內(nèi)容等。又或者是多個(gè)應(yīng)用間相互關(guān)聯(lián)的需要同步查看的事件,這都是極其不方便的。因此我們可以將某些集成到electron軟件中的應(yīng)用或者某些界面用單獨(dú)的窗口打開(kāi)(以下稱(chēng)為獨(dú)立窗口)。
二、實(shí)施方案
1.創(chuàng)建多窗口
首先我們從electron官網(wǎng)中找到創(chuàng)建窗口的方法,electron官網(wǎng)的BrowserWindow,接下來(lái)我們就簡(jiǎn)單寫(xiě)一個(gè)獨(dú)立窗口的創(chuàng)建。這個(gè)窗口可以打開(kāi)外部應(yīng)用也可以是應(yīng)用內(nèi)部。
// windows/CreateIndependentWindow.js
import { BrowserWindow, globalShortcut, ipcMain } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
// 關(guān)于這個(gè)插件,可以看下前幾天我寫(xiě)的解決electron白屏那篇文章
import CreateProcessLoadingPage from './CreateProcessLoadingPage'
/**
* 必傳參數(shù)
* outUrl 外部鏈接
* or
* inUrl 內(nèi)部鏈接
* windowTitle 頁(yè)面標(biāo)題 注意:此值不可重復(fù)
*/
const CreateIndependentWindow = ({
...data
}, win) => {
const obj = {
// 窗口的大小可以通過(guò)傳進(jìn)來(lái)的參數(shù)控制
height: data.height || 640,
width: data.width || 1024,
show: false, // 初始是否可顯示
center: true,
// 窗口是否可以進(jìn)入全屏狀態(tài)
fullscreenable: false,
closable: true, // 窗口是否可關(guān)閉
resizable: true, // 禁止改變主窗口尺寸
webPreferences: {
nodeIntegration: true, // 啟用Node integration
webSecurity: false,
webviewTag: true, // 允許在頁(yè)面內(nèi)使用webview標(biāo)簽
enableRemoteModule: true, // 允許渲染進(jìn)程使用remote模塊
nodeIntegrationInWorker: true, // 在Web工作器中啟用了Node集成
// 允許在子頁(yè)面(iframe)或子窗口(child window)中集成Node.js
nodeIntegrationInSubFrames: true
}
}
// 這里創(chuàng)建窗口實(shí)例
const independentWindow = new BrowserWindow(obj)
// 注冊(cè)全局快捷鍵-打開(kāi)開(kāi)發(fā)者工具(方便查看問(wèn)題)
globalShortcut.register('CommandOrControl+alt+shift+l', () => {
independentWindow.webContents.openDevTools()
})
// 設(shè)置窗口名稱(chēng)
independentWindow.setTitle(data.windowTitle || '人脈旺')
// 這里將當(dāng)前窗口的唯一id,存入全局變量,以容易區(qū)分多個(gè)獨(dú)立窗口
// 變量聲明下方說(shuō)明
global.sharedObject.independentWindow.set(data.windowTitle, independentWindow.webContents.id)
// 聲明打開(kāi)頁(yè)面的url
let winURL = ''
// /IndependentWindow這個(gè)路由是在渲染進(jìn)程創(chuàng)建的承載外部鏈接的獨(dú)立窗口的頁(yè)面
if (process.env.WEBPACK_DEV_SERVER_URL) { // 判斷若為開(kāi)發(fā)環(huán)境
// 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')
}
// 這里是為了獲取拼接需要傳入到頁(yè)面的參數(shù)
const param = Object.keys(data).reduce((pre, cue) => {
return data[cue] ? `${pre}${pre === '?' ? '' : '&'}${cue}=${data[cue]}` : pre
}, '?')
// 使用loadURL方法將頁(yè)面注入到窗口
independentWindow.loadURL(winURL + param)
// 若參數(shù)設(shè)置開(kāi)啟最大化窗口
if (data.maxSize) {
independentWindow.maximize()
}
// 加載頁(yè)面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之后我們?cè)谥鬟M(jìn)程中做一個(gè)監(jiān)聽(tīng),用來(lái)創(chuàng)建獨(dú)立窗口
ipcMain.on('createOtherWindow', (e, data) => { // type窗口類(lèi)型,data 參數(shù)
const name = data.windowTitle
// 判斷當(dāng)前窗口是否已經(jīng)存在, 存在的話 直接喚起
if (global.sharedObject.independentWindow.has(name)) {
const id = global.sharedObject.independentWindow.get(name)
global['independentWindow-' + id].show()
} else {
CreateIndependentWindow(data, win)
}
})這里我們記得聲明一下存儲(chǔ)獨(dú)立窗口id的變量
// background.js
// 多窗口數(shù)據(jù)存儲(chǔ)
global.sharedObject = {
independentWindow: new Map(),
}之后我們?cè)阡秩具M(jìn)程創(chuàng)建一個(gè)頁(yè)面,用來(lái)展示外部鏈接頁(yè)面
<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: {
// 監(jiān)聽(tīng)打開(kāi)webview控制臺(tái)的快捷鍵
eventHandler () {
const webview = document.querySelector('#myWebView')
// 用于查看webview內(nèi)第三方應(yīng)用問(wèn)題,快捷鍵打開(kāi)webview的開(kāi)發(fā)者工具
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>綜上,我們就創(chuàng)建了一個(gè)獨(dú)立窗口,這個(gè)獨(dú)立窗口可以打開(kāi)項(xiàng)目?jī)?nèi)頁(yè)面又或者第三方外部鏈接窗口。
2.多窗口間的通信
electron官方文檔給我們提供了關(guān)于多個(gè)窗口間通訊的方法, 對(duì)于多窗口間的通訊,多是指渲染進(jìn)程間的通訊。 這里我們可以使用ipcRenderer.sendTo()這個(gè)方法,來(lái)進(jìn)行多窗口建的通信。詳見(jiàn)官方文檔說(shuō)明
ipcRenderer.sendTo(webContentsId, channel, ...args)? 以下是官方文檔內(nèi)容
webContentsIdnumberchannelstring...argsany[]
通過(guò) channel 發(fā)送消息到帶有 webContentsId 的窗口.
這里就用到了我們之前在global.sharedObject.independentWindow中存儲(chǔ)的各個(gè)窗口的id。 劃重點(diǎn)一定是窗口實(shí)例的webContentsId的id,而不是窗口的id,別問(wèn)我怎么知道的,問(wèn)也不說(shuō)??????。
// 窗口1中
const remote = window.require('electron').remote
// 通過(guò)窗口名獲取窗口id
const id = remote.getGlobal('sharedObject').independentWindow.get('窗口名windowTitle')
ipcRenderer.sendTo(id, '約定的通信協(xié)議', 參數(shù))
// ===========================-.-===========
// 在另一個(gè)窗口中
ipcRenderer.on('約定的通信協(xié)議', (e, url) => {
//做你想做的
})這樣我們就實(shí)現(xiàn)多窗口渲染進(jìn)程間的通訊。
三、后記
多窗口的場(chǎng)景有人多,有時(shí)候情況可能會(huì)很復(fù)雜,我建議可以將那些特殊作用的窗口,單獨(dú)創(chuàng)建一個(gè),而不是都放到通用的獨(dú)立窗口中,這樣管理起來(lái)會(huì)很方便。
到此這篇關(guān)于vue+electron實(shí)現(xiàn)創(chuàng)建多窗口及窗口間的通信的文章就介紹到這了,更多相關(guān)vue electron多窗口內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
antd upload上傳組件如何獲取服務(wù)端返回?cái)?shù)據(jù)
這篇文章主要介紹了antd upload上傳組件如何獲取服務(wù)端返回?cái)?shù)據(jù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02
Vue3+vite路由配置優(yōu)化(自動(dòng)化導(dǎo)入)
這篇文章主要介紹了Vue3+vite路由配置優(yōu)化(自動(dòng)化導(dǎo)入),需要的朋友可以參考下2023-09-09
使用vue-router在Vue頁(yè)面之間傳遞數(shù)據(jù)的方法
這篇文章主要介紹了使用vue-router在Vue頁(yè)面之間傳遞數(shù)據(jù)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
vue使用formData時(shí)候傳遞參數(shù)是個(gè)空值的情況處理
這篇文章主要介紹了vue使用formData時(shí)候傳遞參數(shù)是個(gè)空值的情況處理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05
vue實(shí)現(xiàn)表格數(shù)據(jù)的增刪改查
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)表格數(shù)據(jù)的增刪改查,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07
Vue el-table組件如何實(shí)現(xiàn)將日期格式化
這篇文章主要介紹了Vue el-table組件如何實(shí)現(xiàn)將日期格式化問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
vue+element-ui+axios實(shí)現(xiàn)圖片上傳
這篇文章主要為大家詳細(xì)介紹了vue+element-ui+axios實(shí)現(xiàn)圖片上傳,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-08-08

