本期内容主要介绍拓展屏的开启以及两个窗口之间的消息通讯。html
在窗口启动这一节里咱们封装了一个createWindow
,用这个来建立一个窗口,拓展屏也是窗口,只不过咱们根据有几个显示屏把其放在对应的外接屏上罢了。vue
咱们在渲染进程添加一个按钮,让其点击以后,向主进程发送对拓展屏的操做(打开或隐藏)node
<a-button type="primary" @click="openScreen">打开拓展屏</a-button> const state = reactive({ open: true, message: '' }) async function openScreen() { await window.ipcRenderer.invoke('win-subScreen', { open: state.open, path: '#/subScreen' }) state.open = !state.open }
主进程接受到以后,经过screen.getAllDisplays()
获取如今窗口的数组(有几个显示屏),而后根据externalDisplay
来获取咱们外接屏幕的信息。
一样的,咱们建立新的窗口也是用createWindow
,以前咱们渲染进程传递了一个path,这个path呢就是咱们拓展屏要展现的页面。
这里须要注意的是createWindow返回的值须要用一个全局变量保存起来,以前托盘的时候说过,若是是局部变量的话,在函数执行完毕以后会被销毁,那么窗口也就被销毁了。
咱们这里用global
赋值是后面窗口通讯会用到,你这里用全局变量赋值时同样的。react
global.js global.tray = null global.willQuitApp = false global.envConfig = {} global.sharedObject = { win: '', subScreen: '' } export default global import { ipcMain, app, screen } from 'electron' import global from '../config/global' import createWindow from './createWindow' import path from 'path' const win = global.sharedObject.win ipcMain.handle('win-subScreen', (_, data) => { if (data.open) { const displays = screen.getAllDisplays() const mainBounds = win.getNormalBounds() const externalDisplay = displays.find((display) => { return display.bounds.x !== 0 || display.bounds.y !== 0 }) if (externalDisplay) { if (global.sharedObject.subScreen) { global.sharedObject.subScreen.show() } else { global.sharedObject.subScreen = createWindow({ frame: false, show: false, parent: win, // win是主窗口 fullscreen: true, webPreferences: { webSecurity: false, contextIsolation: false, enableRemoteModule: true, nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION, plugins: true, preload: path.join(__dirname, 'preload.js'), devTools: false }, x: mainBounds.x < 0 && Math.abs(mainBounds.x) > (win.getContentSize()[0] / 2) ? 0 : externalDisplay.bounds.x, y: externalDisplay.bounds.y }, data.path, `index.html${data.path}`) global.sharedObject.subScreen.once('ready-to-show', () => { global.sharedObject.subScreen.show() }) global.sharedObject.subScreen.on('closed', () => { global.sharedObject.subScreen = null }) } } else { console.log('未检测到拓展屏') } } else { global.sharedObject.subScreen && global.sharedObject.subScreen.destroy() } })
这里呢有个小处理,咱们先判断一下咱们的软件是位于那个屏幕,好比咱们有两个屏,1和2,那么咱们的主窗口和拓展屏应该处于不一样位置,好比:咱们的主窗口在1的话,那么咱们的拓展屏应该在2打开,若是位置相同的话,因为咱们拓展屏设置的是全屏,此时会把主窗口给遮挡住,若是没有设置快捷键关闭的话,那么将没法关闭拓展屏,故有如下处理。git
const mainBounds = win.getNormalBounds() mainBounds为主窗口信息,若是主窗口有一半以上都处于副屏幕的话,那么咱们认为主窗口在副屏,那么拓展屏打开位置应该在主屏,不然的话应该在副屏。 x: mainBounds.x < 0 && Math.abs(mainBounds.x) > (win.getContentSize()[0] / 2) ? 0 : externalDisplay.bounds.x
electorn的窗口间的通讯呢,通常来讲有两种方式。github
WebContents.id
直接发送信息给窗口B。这里介绍几种常见的通讯方式web
ipcRenderer.invoke:渲染进程发送消息给主进程,这是一个promise,能够在其resolve中获取ipcMain.handle的返回值 ipcMain.handle:接收invoke发送的信息,能够return值给ipcRenderer.invoke ipcRenderer.send:渲染进程发送消息给主进程 ipcMain.on:接收send的信息 ipcRenderer.on:接收主进程的消息 webContents.send:主进程发送消息给渲染进程 ipcRenderer.sendTo:能够经过webContentsId直接发送信息到对应的渲染进程窗口
咱们这里把1,2都实现一下vue-cli
渲染进程中能够经过remote
来获取主进程中global
的值,remote.getGlobal('sharedObject').subScreen
就是咱们以前拓展屏的窗口。 transferSub
是咱们的方案1,directSub
是方案2。数组
div class="subMessage"> <a-textarea v-model:value="state.message" :auto-size="{ minRows: 2, maxRows: 5 }" /> <a-button type="primary" :disabled="state.message.length === 0" @click="transferSub">中转发送</a-button> <a-button type="primary" :disabled="state.message.length === 0" @click="directSub">直接发送</a-button> </div> import { defineComponent, reactive, onMounted, onUnmounted, getCurrentInstance } from 'vue' const { remote } = require('electron') const state = reactive({ open: true, message: '' }) const { proxy } = getCurrentInstance() const { $message } = proxy function transferSub() { window.ipcRenderer.invoke('win-subScreen-message', state.message) } function directSub() { const subScreen = remote.getGlobal('sharedObject').subScreen if (subScreen) { window.ipcRenderer.sendTo(subScreen.webContents.id, 'main-subScree', state.message) } } onMounted(() => { window.ipcRenderer.on('subScree-main', (_event, data) => { $message.success(data) }) }) onUnmounted(() => { window.ipcRenderer.removeListener('subScree-main') })
中转一下,用webContents.send
把信息发送给拓展屏窗口promise
ipcMain.handle('win-subScreen-message', (_, data) => { if (global.sharedObject.subScreen) { global.sharedObject.subScreen.webContents.send('renderer-subScreen-message', data) } })
咱们这里直接监听中转的消息以及直接发送的消息,再直接通知主窗口消息。
<template> <div class="subScreen">{{ state.message }}</div> </template> <script> import { defineComponent, reactive, onMounted, onUnmounted } from 'vue' const { remote } = require('electron') export default defineComponent({ setup() { const state = reactive({ message: '' }) onMounted(() => { const win = remote.getGlobal('sharedObject').win window.ipcRenderer.on('renderer-subScreen-message', (_event, data) => { state.message = data window.ipcRenderer.sendTo(win.webContents.id, 'subScree-main', '我收到了中转发送信息') }) window.ipcRenderer.on('main-subScree', (_event, data) => { state.message = data window.ipcRenderer.sendTo(win.webContents.id, 'subScree-main', '我收到了直接发送信息') }) }) onUnmounted(() => { window.ipcRenderer.removeListener('renderer-subScreen-message') window.ipcRenderer.removeListener('main-subScree') }) return { state } } }) </script>
咱们打开拓展屏,在主窗口输入信息,点击直接发送或者中转发送,看看拓展窗口的显示是否为咱们输入的信息,主窗口展现拓展屏的通知信息。
本系列更新只有利用周末和下班时间整理,比较多的内容的话更新会比较慢,但愿能对你有所帮助,请多多star或点赞收藏支持一下