electron27-react-mateos:基于electron+react18仿matePad桌面系统
基于Electron27+React18+ArcoDesign搭建桌面版OS管理系统。
electron-react-mateos 基于最新前端跨端技术栈
electron27.x+react18+arco-design+zustand4+sortablejs
构建的一款仿制matePad界面多层级路由管理OS系统。
ElectronReactOS支持桌面多路由配置,新开窗口+弹窗开启路由页面。
使用技术
- 编码开发:vscode
- 框架技术:electron27+vite4+react18+zustand+react-router
- 打包工具:electron-builder^24.6.4
- 组件库:arco-design (字节react轻量级UI组件库)
- 拖拽组件:sortablejs
- 模拟请求:axios
- 弹窗组件:rdialog (基于react多功能layer弹窗)
- 美化滚动条:rscroll (基于react虚拟滚动条组件)
如何使用electron27创建多窗口,可以去看看这篇分享文章。
https://blog.csdn.net/yanxinyun1990/article/details/134047329
项目结构目录
使用vite4构建工具创建react18项目,遵循react hooks语法编码开发。
electron+react桌面布局
桌面分为顶部栏+桌面端路由菜单+底部Dock菜单三大模块。
<div className="radmin__layout flexbox flex-col">{/* 导航栏 */}<Header />{/* 桌面区域 */}<div className="ra__layout-desktop flex1 flexbox" onContextMenu={handleDeskCtxMenu} style={{marginBottom: 70}}><DeskMenu /></div>{/* Dock菜单 */}<Dock />
</div>
electron实现dock菜单
dock菜单采用背景滤镜模糊效果、支持自适应伸缩、拖拽排序等功能。
<div className="ra__docktool"><div className={clsx('ra__dock-wrap', !dock ? 'compact' : 'split')}>{dockMenu.map((res, key) => {return (<div key={key} className="ra__dock-group">{ res?.children?.map((item, index) => {return (<a key={index} className={clsx('ra__dock-item', {'active': item.active, 'filter': item.filter})} onClick={() => handleDockClick(item)}><span className="tooltips">{item.label}</span><div className="img">{ item.type != 'icon' ? <img src={item.image} /> : <Icon name={item.image} size={32} style={{color: 'inherit'}} /> }</div></a>)})}</div>)})}</div>
</div>
const dockMenu = [{// 图片图标children: [{label: 'Safari', image: '/static/mac/safari.png', active: true},{label: 'Launchpad', image: '/static/mac/launchpad.png'},{label: 'Contacts', image: '/static/mac/contacts.png'},{label: 'Messages', image: '/static/mac/messages.png', active: true}]},{// 自定义iconfont图标children: [{label: 'Home', image: <IconDesktop />, type: 'icon'},{label: 'About', image: 've-icon-about', type: 'icon'}]},{children: [{label: 'Appstore', image: '/static/mac/appstore.png'},{label: 'Mail', image: '/static/mac/mail.png'},{label: 'Maps', image: '/static/mac/maps.png', active: true},{label: 'Photos', image: '/static/mac/photos.png'},{label: 'Facetime', image: '/static/mac/facetime.png'},{label: 'Calendar', image: '/static/mac/calendar.png'},{label: 'Notes', image: '/static/mac/notes.png'},{label: 'Calculator', image: '/static/mac/calculator.png'},{label: 'Music', image: '/static/mac/music.png'}]},{children: [{label: 'System', image: '/static/mac/system.png', active: true, filter: true},{label: 'Empty', image: '/static/mac/bin.png', filter: true}]}
]// 点击dock菜单
const handleDockClick = (item) => {const { label } = itemif(label == 'Home') {createWin({title: '首页',route: '/home',width: 900,height: 600})}else if(label == 'About') {setWinData({ type: 'CREATE_WIN_ABOUT' })}else if(label == 'System') {createWin({title: '网站设置',route: '/setting/system/website',isNewWin: true,width: 900,height: 600})}
}useEffect(() => {const dockGroup = document.getElementsByClassName('ra__dock-group')// 组拖拽for(let i = 0, len = dockGroup.length; i < len; i++) {Sortable.create(dockGroup[i], {group: 'share',handle: '.ra__dock-item',filter: '.filter',animation: 200,delay: 0,onEnd({ newIndex, oldIndex }) {console.log('新索引:', newIndex)console.log('旧索引:', oldIndex)}})}
}, [])
electron+react18实现桌面级路由
/*** Desk桌面多层级路由菜单* Create by andy Q:282310962
*/export default function DeskMenu() {const t = Locales()const filterRoutes = routes.filter(item => !item?.meta?.isWhite)// 桌面二级菜单弹框const DeskPopup = (item) => {const { key, meta, children } = itemreturn (!meta?.isHidden &&<RScroll maxHeight={220}><div className="ra__deskmenu-popup__body">{ children.map(item => {if(item?.children) {return DeskSubMenu(item)}return DeskMenu(item)})}</div></RScroll>)}// 桌面菜单项const DeskMenu = (item) => {const { key, meta, children } = itemreturn (!meta?.isHidden &&<div key={key} className="ra__deskmenu-block"><a className="ra__deskmenu-item" onClick={()=>handleDeskClick(item)} onContextMenu={handleDeskCtxMenu}><div className="img">{meta?.icon ?isImg(meta?.icon) ? <img src={meta.icon} /> : <Icon name={meta.icon} size={40} />:<Icon name="ve-icon-file" size={40} />}</div>{ meta?.name && <span className="title clamp2">{t[meta.name]}</span> }</a></div>)}// 桌面二级菜单项const DeskSubMenu = (item) => {const { key, meta, children } = itemreturn (!meta?.isHidden &&<div key={key} className="ra__deskmenu-block"><a className="ra__deskmenu-item group" onContextMenu={e=>e.stopPropagation()}><Popovertitle={<div className="ra__deskmenu-popup__title">{meta?.name && t[meta.name]}</div>}content={() => DeskPopup(item)}trigger="hover"position="right"triggerProps={{popupStyle: {padding: 5},popupAlign: {right: [10, 45]},mouseEnterDelay: 300,// showArrow: false}}style={{zIndex: 100}}><div className="img">{children.map((child, index) => {if(child?.meta?.isHidden) returnreturn child?.meta?.icon ?isImg(child?.meta?.icon) ? <img key={index} src={child.meta.icon} /> : <Icon key={index} name={child.meta.icon} size={10} />:<Icon key={index} name="ve-icon-file" size={10} />})}</div></Popover>{ meta?.name && <span className="title clamp2">{t[meta.name]}</span> }</a></div>)}// 点击dock菜单const handleDeskClick = (item) => {const { key, meta, element } = itemconst reg = /[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?/if(reg.test(key)) {window.open(key)}else {if(meta?.isNewWin) {// 新窗口打开createWin({title: t[meta?.name] || meta?.title,route: key,width: 900,height: 600})}else {// 弹窗打开rdialog({title: t[meta?.name] || meta?.title,content: <BrowserRouter>{element}</BrowserRouter>,maxmin: true,showConfirm: false,area: ['900px', '550px'],className: 'rc__dialogOS',customStyle: {padding: 0},zIndex: 100})}}}// 右键菜单const handleDeskCtxMenu = (e) => {e.stopPropagation()let pos = [e.clientX, e.clientY]rdialog({type: 'contextmenu',follow: pos,opacity: .1,dialogStyle: {borderRadius: 3, overflow: 'hidden'},btns: [{text: '打开'},{text: '重命名/配置'},{text: '删除',click: () => {rdialog.close()}}]})}useEffect(() => {const deskEl = document.getElementById('deskSortable')Sortable.create(deskEl, {handle: '.ra__deskmenu-block',animation: 200,delay: 0,onEnd({ newIndex, oldIndex }) {console.log('新索引:', newIndex)console.log('旧索引:', oldIndex)}})}, [])return (<div className="ra__deskmenu" id="deskSortable">{ filterRoutes.map(item => {if(item?.children) {return DeskSubMenu(item)}return DeskMenu(item)})}</div>)
}
好了,以上就是electron+react18开发桌面os的一些知识分享。
https://blog.csdn.net/yanxinyun1990/article/details/132825719
https://blog.csdn.net/yanxinyun1990/article/details/131408928
相关文章:

electron27-react-mateos:基于electron+react18仿matePad桌面系统
基于Electron27React18ArcoDesign搭建桌面版OS管理系统。 electron-react-mateos 基于最新前端跨端技术栈electron27.xreact18arco-designzustand4sortablejs构建的一款仿制matePad界面多层级路由管理OS系统。 ElectronReactOS支持桌面多路由配置,新开窗口弹窗开启路…...
高精度算法总结
高精度加法 题目链接: https://www.acwing.com/activity/content/problem/content/825/ 代码模版: #include <iostream> #include <vector>using namespace std;// C A B vector<int> add(vector<int> &A, vector<…...

EMQX-5.3.1单机集群部署并基于Nginx实现负载均衡
本例单机集群部署使用三个节点,分别为node1、node2、node3 一、安装与配置 1 创建数据目录 mkdir -p node1/data node1/logs mkdir -p node2/data node2/logs mkdir -p mode3/data node3/logs 2 数据目录授权 chown 1000 node1/ node2/ node3/ chown 1000 n…...
电商又有大动静,又一短视频进军电商领域!
我是电商珠珠 电商近几年来发展迅速,截止到23年的10月26日,电商零售平台市场份额是淘宝市场占比的53%,京东为20%,拼多多手握15%的市场占比,三者合计份额已经达到了88%。 剩下的抖音、快手、苏宁也在奋力抢占更多。 …...

C语言线性表的链式存储(框架)
线性表的链式存储 线性表的顺序存储:用一块连续的内存空间 线性表的链式存储:不连续的内存空间 链表是由一系列的节点组成,每个节点包含两个域,一个是数据域,一个是指针域 链表的插入和删除原理 单项链表框架的搭建 …...
webpack配置完热更新之后还是会刷新整个页面
可以在webpack文档中找到有关热更新的详细信息,意思就是,开启热更新之后,整个页面你改了哪里,就只更新哪里,其他没变的,或者保存在缓存里面的内容,都不会改变,感谢很神奇!…...
2023年第六届传智杯程序设计挑战赛(个人赛)B组 赛后复盘
传智杯赛后复盘 大家好 我是寸铁👊 2023年第六届传智杯程序设计挑战赛(个人赛)B组 赛后复盘 喜欢的小伙伴可以点点关注 💝 1. 字符串拼接 细节:一定要清楚nextLine()和next()的区别 nextLine()是遇到回车会停下来 nex…...

C语言——深入理解指针(2)
目录 1. 数组名 2. 指针访问数组 3. 一维数组的传参(本质) 4. 冒泡排序 5. 二级指针 6. 指针数组(指针的数组) 7. 指针数组模拟二维数组 1. 数组名 在之前的代码中我们使用指针访问过数组的内容。 int arr[10] {1,2,3,4…...
【已解决】HBase 2.2.6 集群部署后,从节点未启动 HRegionServer
问题发现 今天搭建了 HBase 2.2.6 集群环境,启动之后发现,从节点的 HRegionServer 未启动。多次对比参数设置仍然未发现异常。而启动之前的 HBase 2.4.11 则完成正常,我就有点怀疑是不是 HBase 2.2.6 集群搭建有什么特殊的地方? …...

JVM——垃圾回收(方法区中的垃圾回收和(堆回收)自动垃圾回收)
目录 1.自动垃圾回收介绍1.C/C的内存管理2.Java的内存管理3.垃圾回收的对比 2.方法区的回收方法区的回收 – 手动触发回收 3.堆回收1.引用计数法2.可达性分析算法 1.自动垃圾回收介绍 1.C/C的内存管理 ⚫ 在C/C这类没有自动垃圾回收机制的语言中,一个对象如果不再…...

Flink 常用物理分区算子(Physical Partitioning)
Flink 物理分区算子(Physical Partitioning) 在Flink中,常见的物理分区策略有:随机分配(Random)、轮询分配(Round-Robin)、重缩放(Rescale)和广播(Broadcast)。 接下来,我们通过源码和Demo分别了解每种物理分区算子的作用和区别。 (1) 随机…...
Leetcode.560 和为 K 的子数组
题目链接 Leetcode.560 和为 K 的子数组 mid 题目描述 给你一个整数数组 n u m s nums nums 和一个整数 k k k ,请你统计并返回 该数组中和为 k k k 的子数组的个数 。 子数组是数组中元素的连续非空序列。 示例 1: 输入:nums [1,1,1]…...

linklab phase1 更简单的方法
直接反汇编phase1.o,看eax中是0x21,0x21在数据域中,直接把从第21个字节的内容改为0000000000即可。...

8.前端--CSS-文本属性【2023.11.26】
CSS Text(文本)属性可定义文本的外观,比如文本的颜色、对齐文本、修饰文本、文本缩进、行间距等 1.文本颜色 color 属性用于定义文本的颜色。 语法: div { color: red; }属性: 2.文本对齐 text-align 属性用于设置元…...

容器技术——Cgroup
目录 容器技术容器技术概述要区分好共享与隔离的概念容器技术的三大核心容器对比虚拟机 namespaceUnionFs容器操作系统的来源操作系统的来源完整操作系统的镜像docker image是什么?如何构成的 如何为容器安装操作系统UnionFS(联合文件系统)的…...
uniapp+vue3路由跳转传参
在uni-app中使用Vue 3进行路由跳转传参,可以通过以下步骤实现: 1.在router文件夹中创建一个名为index.js的文件,用于配置路由。在这个文件中,我们将导入createRouter和createWebHistory函数,并定义路由规则。同时&…...
流量主如何在广告收益和用户体验中找到平衡
流量主在广告收益和用户体验之间找到平衡是一个关键的挑战,因为过多或不恰当的广告可能会影响到用户的满意度和留存率。以下是一些方法,可以帮助流量主在这两者之间找到平衡: admaoyan猫眼聚合 优质内容为先: 提供高质量、有价值的…...

RPC和HTTP的区别
目录 1、RPC是什么 1.1 概念 1.2 RPC的组成部分 1.3 常见的 RPC 技术和框架 1.4 RPC的工作流程 2、HTTP是什么 2.1 概念 2.2 HTTP的消息格式 2.3 HTTP响应状态码有哪些 3、⭐RPC和HTTP的区别 小结 1、RPC是什么 1.1 概念 RPC(Remote Procedure Call&am…...

Dubbo3使用Zookeeper作为注册中心的方案讨论!详解DubboAdmin与PrettyZoo来监控服务的优劣!
文章目录 一:Dubbo注册中心的基本使用 二:Zookeeper注册中心的使用 1:依赖引入 2:实际开发 三:Zookeeper作为注册中心的使用展示 1:启动注册Zookeeper服务 2:引入注册中心 (一)…...
前端uni微信小程序和后端nodejs使用websoket
需求 前端向后台服务器发请求获取验证码,然后端游输入验证码,向我的后端发请求获取验证信息。后台给游戏端返回信息的时候同时给微信小程序端返回验证结果。意思是不要微信小程序端主动触发,验证是否绑定的请求。 思路 后端生成验证码时存…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...

【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...

springboot 日志类切面,接口成功记录日志,失败不记录
springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...

保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!
目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...