当前位置: 首页 > news >正文

基于electron25+vite4创建多窗口|vue3+electron25新开模态窗体

在写这篇文章的时候,查看了下electron最新稳定版本由几天前24.4.0升级到了25了,不得不说electron团队迭代速度之快!

前几天有分享一篇electron24整合vite4全家桶技术构建桌面端vue3应用示例程序。

https://www.cnblogs.com/xiaoyan2017/p/17436076.html

这次继续接着上次项目,主要介绍electron25结合vue3技术实现创建多开窗口及窗口间主/渲染进程通信知识。

随着electron快速更新,结合vite的高效构建运行速度,现在新开一个独立窗口,打开速度极快。

electron官网主进程模块BrowserWindow用于创建一个新窗口的方法,提供了非常丰富的API操作用法。

BrowserWindow | Electron

复制代码

// In the main process.
const { BrowserWindow } = require('electron')const win = new BrowserWindow({ width: 800, height: 600 })// Load a remote URL
win.loadURL('https://github.com')// Or load a local HTML file
win.loadFile('index.html')

复制代码

如果每次都new一个BrowserWindow窗口,显得有些笨拙且复杂。今天要分享的是封装BrowserWindow方法,只需传入配置参数,即可快速生成一个独立窗口。

复制代码

createWin({title: '关于About.vue',route: '/about',width: 600,height: 400,background: '#fafffa',resize: true
})

复制代码

新建一个windows/index.js文件。

复制代码

/*** 封装多窗口管理器* @author YXY*/const { app, BrowserWindow, ipcMain } = require('electron')
const { join } = require('path')process.env.ROOT = join(__dirname, '../../')const isDevelopment = process.env.NODE_ENV == 'development'
// const winURL = isDevelopment ? 'http://localhost:3000/' : join(__dirname, 'dist/index.html')
const winURL = isDevelopment ? process.env.VITE_DEV_SERVER_URL : join(process.env.ROOT, 'dist/index.html')// 配置参数
const defaultConfig = {id: null,               // 窗口唯一idbackground: '#fff',     // 背景色route: '',              // 路由地址urltitle: '',              // 标题data: null,             // 传入数据参数width: '',              // 窗口宽度height: '',             // 窗口高度minWidth: '',           // 窗口最小宽度minHeight: '',          // 窗口最小高度x: '',                  // 窗口相对于屏幕左侧坐标y: '',                  // 窗口相对于屏幕顶端坐标resize: true,           // 是否支持缩放maximize: false,        // 最大化窗口isMultiWin: false,      // 是否支持多开窗口isMainWin: false,       // 是否主窗口parent: '',             // 父窗口(需传入父窗口id)modal: false,           // 模态窗口(模态窗口是浮于父窗口上,禁用父窗口)alwaysOnTop: false      // 置顶窗口
}class MultiWindows {constructor() {// 主窗口this.mainWin = null// 窗口组this.winLs = {}// ...}winOpts() {return {// 窗口图标icon: join(process.env.ROOT, 'resource/shortcut.ico'),backgroundColor: '#fff',autoHideMenuBar: true,titleBarStyle: 'hidden',width: 1000,height: 640,resizable: true,minimizable: true,maximizable: true,frame: false,show: false,webPreferences: {contextIsolation: true, // 启用上下文隔离(为了安全性)(默认true)// nodeIntegration: false, // 启用Node集成(默认false)preload: join(process.env.ROOT, 'resource/preload.js'),// devTools: true,// webSecurity: false}}}// 创建新窗口createWin(options) {const args = Object.assign({}, defaultConfig, options)console.log(args)// 判断窗口是否存在for(let i in this.winLs) {if(this.getWin(i) && this.winLs[i].route === args.route && !this.winLs[i].isMultiWin) {this.getWin(i).focus()return}}let opt = this.winOpts()if(args.parent) {opt.parent = this.getWin(args.parent)}if(typeof args.modal === 'boolean') opt.modal = args.modalif(typeof args.resize === 'boolean') opt.resizable = args.resizeif(typeof args.alwaysOnTop === 'boolean') opt.alwaysOnTop = args.alwaysOnTopif(args.background) opt.backgroundColor = args.backgroundif(args.width) opt.width = args.widthif(args.height) opt.height = args.heightif(args.minWidth) opt.minWidth = args.minWidthif(args.minHeight) opt.minHeight = args.minHeightif(args.x) opt.x = args.xif(args.y) opt.y = args.yconsole.log(opt)// 创建窗口对象let win = new BrowserWindow(opt)// 是否最大化if(args.maximize && args.resize) {win.maximize()}this.winLs[win.id] = {route: args.route, isMultiWin: args.isMultiWin}args.id = win.id// 加载页面let $urlif(!args.route) {if(process.env.VITE_DEV_SERVER_URL) {// 打开开发者调试工具// win.webContents.openDevTools()$url = process.env.VITE_DEV_SERVER_URL}else {$url = winURL}}else {$url = `${winURL}#${args.route}`}win.loadURL($url)/*if(process.env.VITE_DEV_SERVER_URL) {win.loadURL($url)}else {win.loadFile($url)}*/win.webContents.openDevTools()win.once('ready-to-show', () => {win.show()})win.on('close', () => win.setOpacity(0))// 初始化渲染进程win.webContents.on('did-finish-load', () => {// win.webContents.send('win-loaded', '加载完成~!')win.webContents.send('win-loaded', args)})}// 获取窗口getWin(id) {return BrowserWindow.fromId(Number(id))}// 获取全部窗口getAllWin() {return BrowserWindow.getAllWindows()}// 关闭全部窗口closeAllWin() {try {for(let i in this.winLs) {if(this.getWin(i)) {this.getWin(i).close()}else {app.quit()}}} catch (error) {console.log(error)}}// 开启主进程监听ipcMainListen() {// 设置标题ipcMain.on('set-title', (e, data) => {const webContents = e.senderconst wins = BrowserWindow.fromWebContents(webContents)wins.setTitle(data)// const wins = BrowserWindow.getFocusedWindow()// wins.setTitle('啦啦啦')})// 是否最大化(方法一)/*ipcMain.on('isMaximized', e => {const win = BrowserWindow.getFocusedWindow()e.sender.send('mainReplay', win.isMaximized())})*/// 是否最大化(方法二)ipcMain.handle('isMaximized', (e) => {const win = BrowserWindow.getFocusedWindow()return win.isMaximized()})ipcMain.on('min', e => {const win = BrowserWindow.getFocusedWindow()win.minimize()})ipcMain.handle('max2min', e => {const win = BrowserWindow.getFocusedWindow()if(win.isMaximized()) {win.unmaximize()return false}else {win.maximize()return true}})ipcMain.on('close', (e, data) => {// const wins = BrowserWindow.getFocusedWindow()// wins.close()this.closeAllWin()})// ...}
}module.exports = MultiWindows

复制代码

在主进程入口background.js文件引入封装窗口。

复制代码

const { app, BrowserWindow, ipcMain } = require('electron')
const { join } = require('path')const MultiWindows = require('./src/windows')// 屏蔽安全警告
// ectron Security Warning (Insecure Content-Security-Policy)
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'const createWindow = () => {let window = new MultiWindows()window.createWin({isMainWin: true})window.ipcMainListen()
}app.whenReady().then(() => {createWindow()app.on('activate', () => {if (BrowserWindow.getAllWindows().length === 0) createWindow()})
})app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit()
})

复制代码

在主进程中做一个ipcMain监听,用来创建独立窗口。

ipcMain.on('win-create', (event, args) => this.createWin(args))

新建windows/action.js文件,处理渲染器进程到主进程的异步通信,可以发送同步或异步的消息到主进程,也可以接收主进程发送的消息。

复制代码

/*** 创建新窗口* @param {object} args | {width: 640, height: 480, route: '/home'}*/
export function createWin(args) {window.electronAPI.send('win-create', args)
}/*** 设置窗口* @param {string} type | 'show'/'hide'/'close'/'min'/'max'/'max2min'/'restore'/'reload'* @param {number} id*/
export function setWin(type, id) {window.electronAPI.send('win-' + type, id)
}/*** 创建登录窗口*/
export function loginWin() {createWin({isMainWin: true,title: '登录',route: '/login',width: 550,height: 320,resize: false,alwaysOnTop: true,})
}

复制代码

在vue页面中调用上面封装的方法。

复制代码

<template><div class="home">...<Button type="success" @click="openWin">打开Manage窗口(设置parent)</Button><Button type="success" @click="openWin1">打开Me窗口(设置resizable/isMultiWin)</Button><Button type="success" @click="openWin2">打开User窗口</Button></div>
</template><script>
import { winCfg, createWin } from '@/windows/action'export default {name: 'Home',setup() {const openWin = () => {MessageBox.confirm('提示', '确定打开Manage页面吗? 【设置parent属性】', {callback: action => {if(action == 'confirm') {createWin({title: 'Manage.vue',route: '/manage',width: 600,height: 400,background: '#09f',parent: winCfg.window.id,// modal: true})}else if(action == 'cancel') {Message.info('您已取消!')}}})}const openWin1 = () => {// 左上角// let posX = 0// let posY = 0// 右下角let posX = window.screen.availWidth - 850let posY = window.screen.availHeight - 600MessageBox.confirm('提示', '确定打开Me页面吗?', {callback: action => {if(action == 'confirm') {createWin({title: 'Me.vue',route: '/me?name=Andy',width: 850,height: 600,x: posX,y: posY,background: 'yellow',resize: false,isMultiWin: true,maximize: true})}else if(action == 'cancel') {Message.info('您已取消!')}}})}const openWin2 = () => {MessageBox.confirm('提示', '确定打开User页面吗?', {callback: action => {if(action == 'confirm') {createWin({title: 'User.vue',route: '/user',width: 700,height: 550,minWidth: 300,minHeight: 300,data: {name: 'Andy',age: 20},background: 'green',isMultiWin: true})}else if(action == 'cancel') {Message.info('您已取消!')}}})}// ...return {openWin,openWin1,openWin2,// ...}}
}
</script>

复制代码

设置 frame: false 创建无边框窗口。

设置 -webkit-app-region: drag 来实现自定义拖拽区域。设置后的按钮操作无法响应其它事件,只需设置 -webkit-app-region: no-drag 即可实现响应事件。

electron+vite提供的一些环境变量。

process.env.NODE_ENV 
process.env.VITE_DEV_SERVER_URL

在开发环境,加载vite url,生产环境,则加载vite build出来的html。

Ok,综上就是electron25+vite4结合构建跨端应用的一些分享,希望对大家有所帮助哈~~

相关文章:

基于electron25+vite4创建多窗口|vue3+electron25新开模态窗体

在写这篇文章的时候&#xff0c;查看了下electron最新稳定版本由几天前24.4.0升级到了25了&#xff0c;不得不说electron团队迭代速度之快&#xff01; 前几天有分享一篇electron24整合vite4全家桶技术构建桌面端vue3应用示例程序。 https://www.cnblogs.com/xiaoyan2017/p/17…...

红米手机 导出 通讯录 到电脑保存

不要搞什么 云服务 不要安装什么 手机助手 不要安装 什么app 用 usb 线 连接 手机 和 电脑 手机上会跳出 提示 选择 仅传输文件 会出现下面的 一个 盘 进入 MIUI目录 然后进入 此电脑\Redmi Note 5\内部存储设备\MIUI\backup\AllBackup\20230927_043337 如何没有上面的文件&a…...

常见web信息泄露

一、源码(备份文件)泄露 1、git泄露 Git是一个开源的分布式版本控制系统&#xff0c;在执行git init初始化目录的时候&#xff0c;会在当前目录下自动创建一个.git目录&#xff0c;用来记录代码的变更记录等。发布代码的时候&#xff0c;如果没有把.git这个目录删除&#xff…...

找不到VCRUNTIME140_1.dll怎么办,VCRUNTIME140_1.dll丢失的5个解决方法

在当今的数字时代&#xff0c;我们的生活和工作都离不开电脑。然而&#xff0c;随着科技的发展&#xff0c;我们也会遇到各种各样的问题。其中&#xff0c;VCRUNTIME140_1.dll丢失的问题是许多人都会遇到的困扰。这个问题可能会导致许多应用程序无法正常运行&#xff0c;给我们…...

C#生成自定义海报

安装包 SixLabors.ImageSharp.Drawing 2.0 需要的字体&#xff1a;宋体和微软雅黑 商用的需要授权如果商业使用可以使用方正书宋、方正黑体&#xff0c;他们可以免费商用 方正官网 代码 using SixLabors.Fonts; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Draw…...

BP神经网络的MATLAB实现(含源代码)

BP(back propagation)神经网络是1986年由Rumelhart和McClelland为首的科学家提出的概念&#xff0c;是一种按照误差逆向传播算法训练的多层前馈神经网络&#xff0c;是应用最广泛的神经网络模型之一 具体数学推导以及原理在本文不做详细介绍&#xff0c;本文将使用MATLAB进行B…...

AES和Rijndael的区别

快速链接: . 👉👉👉 个人博客笔记导读目录(全部) 👈👈👈 付费专栏-付费课程 【购买须知】:密码学实践强化训练–【目录】 👈👈👈“Rijndael” 这个词的中文谐音可以近似地发音为 “瑞恩达尔”。请注意,这只是一种近似的发音方式,因为该词是荷兰姓氏 “Ri…...

【数据结构】—堆详解(手把手带你用C语言实现)

食用指南&#xff1a;本文在有C基础的情况下食用更佳 &#x1f525;这就不得不推荐此专栏了&#xff1a;C语言 ♈️今日夜电波&#xff1a;水星—今泉愛夏 1:10 ━━━━━━️&#x1f49f;──────── 4:23 …...

关于算法复杂度的几张表

算法在改进今天的计算机与古代的计算机的区别 去除冗余 数据点 算法复杂度 傅里叶变换...

蓝桥杯每日一题2023.10.1

路径 - 蓝桥云课 (lanqiao.cn) 题目分析 求最短路问题&#xff0c;有多种解法&#xff0c;下面介绍两种蓝桥杯最常用到的两种解法 方法一 Floyd&#xff08;求任意两点之间的最短路&#xff09;注&#xff1a;不能有负权回路 初始化每个点到每个点的距离都为0x3f这样才能对…...

第三章:最新版零基础学习 PYTHON 教程(第十节 - Python 运算符—Python 中的运算符重载)

运算符重载意味着赋予超出其预定义操作含义的扩展含义。例如,运算符 + 用于添加两个整数以及连接两个字符串和合并两个列表。这是可以实现的,因为“+”运算符被 int 类和 str 类重载。您可能已经注意到,相同的内置运算符或函数对于不同类的对象显示不同的行为,这称为运算符…...

Nacos 实现服务平滑上下线(Ribbon 和 LB)

前言 不知道各位在使用 SpringCloud Gateway Nacos的时候有没有遇到过服务刚上线偶尔会出现一段时间的503 Service Unavailable&#xff0c;或者服务下线后&#xff0c;下线服务仍然被调用的问题。而以上问题都是由于Ribbon或者LoadBalancer的默认处理策略有关&#xff0c;其…...

c/c++里 对 共用体 union 的内存分配

对union 的内存分配&#xff0c;是按照最大的那个成员分配的。 谢谢...

博途SCL区间搜索指令(判断某个数属于某个区间)

S型速度曲线行车位置控制,停靠位置搜索功能会用到区间搜索指令,下面我们详细介绍区间搜索指令的相关应用。 S型加减速行车位置控制(支持点动和停车位置搜索)-CSDN博客S型加减速位置控制详细算法和应用场景介绍,请查看下面文章博客。本篇文章不再赘述,这里主要介绍点动动和…...

(三)激光线扫描-中心线提取

光条纹中心提取算法是决定线结构光三维重建精度以及光条纹轮廓定位准确性的重要因素。 1. 光条的高斯分布 激光线条和打手电筒一样,中间最亮,越像周围延申,光强越弱,这个规则符合高斯分布,如下图。 2. 传统光条纹中心提取算法 传统的光条纹中心提取算法有 灰度重心法、…...

递归与分治算法(1)--经典递归、分治问题

目录 一、递归问题 1、斐波那契数列 2、汉诺塔问题 3、全排列问题 4、整数划分问题 二、递归式求解 1、代入法 2、递归树法 3、主定理法 三、 分治问题 1、二分搜索 2、大整数乘法 一、递归问题 1、斐波那契数列 斐波那契数列不用过多介绍&#xff0c;斐波那契提出…...

Java之SpringCloud Alibaba【六】【Alibaba微服务分布式事务组件—Seata】

一、事务简介 事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。 在关系数据库中&#xff0c;一个事务由一组SQL语句组成。 事务应该具有4个属性: 原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。 原子性(atomicity) ∶个事务…...

Android逆向学习(五)app进行动态调试

Android逆向学习&#xff08;五&#xff09;app进行动态调试 一、写在前面 非常抱歉鸽了那么久&#xff0c;前一段时间一直在忙&#xff0c;现在终于结束了&#xff0c;可以继续更新android逆向系列的&#xff0c;这个系列我会尽力做下去&#xff0c;然后如果可以的话我看看能…...

音频编辑软件Steinberg SpectraLayers Pro mac中文软件介绍

Steinberg SpectraLayers Pro mac是一款专业的音频编辑软件&#xff0c;旨在帮助音频专业人士进行精细的音频编辑和声音处理。它提供了强大的频谱编辑功能&#xff0c;可以对音频文件进行深入的频谱分析和编辑。 Steinberg SpectraLayers Pro mac软件特点 1. 频谱编辑&#xff…...

基于.Net Core实现自定义皮肤WidForm窗口

前言 今天一起来实现基于.Net Core、Windows Form实现自定义窗口皮肤&#xff0c;并实现窗口移动功能。 素材 准备素材&#xff1a;边框、标题栏、关闭按钮图标。 窗体设计 1、创建Window窗体项目 2、窗体设计 拖拉4个Panel控件&#xff0c;分别用于&#xff1a;标题栏、关…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...