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 } = item
    if(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 } = item

        return (
            !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 } = item

        return (
            !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 } = item

        return (
            !meta?.isHidden &&
            <div key={key} className="ra__deskmenu-block">
                <a className="ra__deskmenu-item group" onContextMenu={e=>e.stopPropagation()}>
                    <Popover
                        title={<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) return
                                return 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 } = item

        const 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

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/179662.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[Halcon检测] 划痕检测之高斯导数提取

&#x1f4e2;博客主页&#xff1a;https://loewen.blog.csdn.net&#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;本文由 丶布布原创&#xff0c;首发于 CSDN&#xff0c;转载注明出处&#x1f649;&#x1f4e2;现…

【开源】基于Vue和SpringBoot的大学生相亲网站

项目编号&#xff1a; S 048 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S048&#xff0c;文末获取源码。} 项目编号&#xff1a;S048&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询会员4…

解决Activiti5.22流程图部署在Windows上正常,但在linux上部署后出现中文变方块的问题

总结/朱季谦 楼主最近在做公司的工作流平台&#xff0c;发现一个很无语的事情&#xff0c;Activiti5.22的流程图在Windows环境上部署&#xff0c;是可以正常查看的&#xff0c;但发布到公司的Linux服务器上后&#xff0c;在上面进行流程图在线部署时&#xff0c;发现中文都变成…

人工智能-循环神经网络的简洁实现

循环神经网络的简洁实现 如何使用深度学习框架的高级API提供的函数更有效地实现相同的语言模型。 我们仍然从读取时光机器数据集开始。 import torch from torch import nn from torch.nn import functional as F from d2l import torch as d2lbatch_size, num_steps 32, 35…

【开源】基于Vue和SpringBoot的学校热点新闻推送系统

项目编号&#xff1a; S 047 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S047&#xff0c;文末获取源码。} 项目编号&#xff1a;S047&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 新闻类型模块2.2 新闻档案模块2.3 新…

【深度学习】卷积神经网络(CNN)

一、引子————边界检测 我们来看一个最简单的例子&#xff1a;“边界检测&#xff08;edge detection&#xff09;”&#xff0c;假设我们有这样的一张图片&#xff0c;大小88&#xff1a; 图片中的数字代表该位置的像素值&#xff0c;我们知道&#xff0c;像素值越大&#…

ubuntu上查看各个进程的实时CPUMEM占用的办法

top常见参数top界面分析system monitorhtop1、查看htop的使用说明2、显示树状结构3、htop使用好文推荐top top的用法应该是最为普遍的 常见参数 -d 更新频率,top显示的界面几秒钟更新一次 -n 更新的次数,top显示的界面更新多少次之后就自动结束了 当然也可以将top日志通过…

3分钟使用 WebSocket 搭建属于自己的聊天室(WebSocket 原理、应用解析)

文章目录 WebSocket 的由来WebSocket 是什么WebSocket 优缺点优点缺点 WebSocket 适用场景主流浏览器对 WebSocket 的兼容性WebSocket 通信过程以及原理建立连接具体过程示例Sec-WebSocket-KeySec-WebSocket-Extensions 数据通信数据帧帧头&#xff08;Frame Header&#xff09…

Pandas一键爬取解析代理IP与代理IP池的维护

目录 前言 一、获取代理IP 二、解析代理IP 三、维护代理IP池 四、完整代码 总结 前言 在爬虫过程中&#xff0c;我们经常会使用代理IP来绕过一些限制&#xff0c;比如防止被封IP等问题。而代理IP的获取和维护是一个比较麻烦的问题&#xff0c;需要花费一定的时间和精力。…

机器学习/sklearn 笔记:K-means,kmeans++,MiniBatchKMeans

1 K-means介绍 1.0 方法介绍 KMeans算法通过尝试将样本分成n个方差相等的组来聚类&#xff0c;该算法要求指定群集的数量。它适用于大量样本&#xff0c;并已在许多不同领域的广泛应用领域中使用。KMeans算法将一组样本分成不相交的簇&#xff0c;每个簇由簇中样本的平均值描…

Ocam——自由录屏工具~

当我们想要做一些混剪、恶搞类型的视频时&#xff0c;往往需要源影视作品中的诸多素材&#xff0c;虽然可以通过裁减mp4文件的方式来获取片段&#xff0c;但在高画质的条件下&#xff0c;mp4文件本身通常会非常大&#xff0c;长此以往&#xff0c;会给剪辑工作带来诸多不便&…

使用 PowerShell 创建共享目录

在 Windows 中&#xff0c;可以使用共享目录来将文件和文件夹共享给其他用户或计算机。共享目录可以通过网络访问&#xff0c;这使得它们非常适合用于文件共享、协作和远程访问。 要使用 PowerShell 创建共享目录&#xff0c;可以使用 New-SmbShare cmdlet。New-SmbShare cmdl…

arduino入门一:点亮第一个led

void setup() { pinMode(12, OUTPUT);//12引脚设置为输出模式 } void loop() { digitalWrite(12, HIGH);//设置12引脚为高电平 delay(1000);//延迟1000毫秒&#xff08;1秒&#xff09; digitalWrite(12, LOW);//设置12引脚为低电平 delay(1000); }

聚观早报 |快手Q3营收;拼多多杀入大模型;Redmi K70E开启预约

【聚观365】11月23日消息 快手Q3营收 拼多多杀入大模型 Redmi K70E开启预约 华为nova 12系列或下周发布 亚马逊启动“AI就绪”新计划 快手Q3营收 财报显示&#xff0c;快手第三季度营收279亿元&#xff0c;同比增长20.8%&#xff1b;期内盈利21.8亿元&#xff0c;去年同期…

2023 年 亚太赛 APMCM (A题)国际大学生数学建模挑战赛 |数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时&#xff0c;你是否曾经感到茫然无措&#xff1f;作为2022年美国大学生数学建模比赛的O奖得主&#xff0c;我为大家提供了一套优秀的解题思路&#xff0c;让你轻松应对各种难题。 完整内容可以在文章末尾领取&#xff01; 问题1 图像处理&am…

免费多域名SSL证书

顾名思义&#xff0c;免费多域名SSL证书就是一种能够为多个域名或子域提供HTTPS安全保护的证书。这意味着&#xff0c;如果您有三个域名——例如example.com、example.cn和company.com&#xff0c;您可以使用一个免费的多域名SSL证书为所有这些域名提供安全保障&#xff0c;而无…

Missing file libarclite_iphoneos.a 问题解决方案

问题 在Xcode 运行项目会报以下错误 File not found: /Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphoneos.a解决方案 打开URL https://github.com/kamyarelyasi/Libarclite-Files &#xff0c;下载liba…

解决Android端libc++_shared.so库冲突问题

前言 随着App功能增多&#xff0c;集成的so库也会增多&#xff0c;如果系统中多个so库都使用系统自动生成的libc_shared.so库&#xff0c;如果多个SDK都有该so包&#xff0c;就会出现报错&#xff1a; 解决办法 如果出现该问题&#xff0c;说明您的项目中有多个SDK共同依赖了C标…

什么?Postman也能测WebSocket接口了?

01 WebSocket 简介 WebSocket是一种在单个TCP连接上进行全双工通信的协议。 WebSocket使得客户端和服务器之间的数据交换变得更加简单&#xff0c;允许服务端主动向客户端推送数据。在WebSocket API中&#xff0c;浏览器和服务器只需要完成一次握手&#xff0c;两者之间就直接…

牛客 最小公配数 golang版实现

题目请参考: HJ108 求最小公倍数 题解: 在大的数的倍数里面去找最小的能整除另外一个数的数&#xff0c;就是最小公倍数&#xff0c;按照大的来找&#xff0c;循环次数能够降到很少&#xff0c;提升效率 golang实现: package mainimport ("fmt" )func main() {a : …