Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

  • Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面已关闭评论
  • 79 次浏览
  • A+
所属分类:Web前端
摘要

基于React18+Electron27+ArcoDesign 仿macOS桌面端系统框架ElectronMacOS。 electron-react-macOs 基于electron27.x+vite4+react18+arcoDesign+zustand 等技术构建桌面版仿MacOs框架系统解决方案。支持中英文/繁体、dark+light主题、桌面多层级路由、多窗口路由页面、动态换肤、Dock悬浮菜单 等功能。

基于React18+Electron27+ArcoDesign仿macOS桌面端系统框架ElectronMacOS

electron-react-macOs 基于electron27.x+vite4+react18+arcoDesign+zustand等技术构建桌面版仿MacOs框架系统解决方案。支持中英文/繁体、dark+light主题、桌面多层级路由、多窗口路由页面、动态换肤、Dock悬浮菜单等功能。

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

ElectronReactOS系统是首创自研的桌面多层级路由菜单、支持electron多开窗口+弹窗路由窗口

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

技术栈

  • 开发工具:vscode
  • 框架技术:vite4+react18+zustand+react-router
  • 跨端技术:electron^27.0.1
  • 打包工具:electron-builder^24.6.4
  • UI组件库:arco-design (字节react轻量级UI组件库)
  • 图表组件:bizcharts^4.1.23
  • 拖拽库:sortablejs
  • 模拟请求:axios
  • 弹窗组件:rdialog (基于react多功能layer弹窗)
  • 美化滚动条:rscroll (基于react虚拟滚动条组件)

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

特性

  1. 桌面路由页面支持暗黑+亮色模式
  2. 内置中英文/繁体国际化
  3. 经典桌面Dock悬浮菜单
  4. 可拖拽桌面路由+程序坞Dock菜单
  5. 桌面路由支持多个子级路由配置
  6. 动态视觉效果,自定义桌面换肤背景
  7. 可视化多窗口路由,支持electron新开窗口+rdialog弹窗页面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

大家如果对Electron封装多窗口感兴趣,可以去看看下面这篇分享文章。

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

项目结构

使用vite4构建react18项目,整合electron跨端技术,搭建桌面版OS管理系统。

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron桌面os布局模板

桌面os布局分为顶部操作栏+桌面端路由菜单+底部Dock菜单三大模块。

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

<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+React实现Dock菜单

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

底部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+React桌面多级路由菜单

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面

如上图:桌面菜单配置支持多级路由。

import { lazy } from 'react' import {     IconDesktop, IconDashboard, IconLink, IconCommand, IconUserGroup, IconLock,     IconSafe, IconBug, IconUnorderedList, IconStop } from '@arco-design/web-react/icon' import Layout from '@/layouts' import Desk from '@/layouts/desk' import Blank from '@/layouts/blank' import lazyload from '../lazyload'  export default [     /* 桌面模块 */     {         path: '/desk',         key: '/desk',         element: <Desk />,         meta: {             icon: <IconDesktop />,             name: 'layout__main-menu__desk',             title: 'Appstore',             isWhite: true, // 路由白名单             isAuth: true, // 需要鉴权             isHidden: false, // 是否隐藏菜单         }     },      {         path: '/home',         key: '/home',         element: <Layout>{lazyload(lazy(() => import('@views/home')))}</Layout>,         meta: {             icon: '/static/mac/appstore.png',             name: 'layout__main-menu__home-index',             title: '首页',             isAuth: true,             isNewWin: true         }     },     {         path: '/dashboard',         key: '/dashboard',         element: <Layout>{lazyload(lazy(() => import('@views/home/dashboard')))}</Layout>,         meta: {             icon: <IconDashboard />,             name: 'layout__main-menu__home-workplace',             title: '工作台',             isAuth: true         }     },     {         path: 'https://react.dev/',         key: 'https://react.dev/',         meta: {             icon: <IconLink />,             name: 'layout__main-menu__home-apidocs',             title: 'react.js官方文档',             rootRoute: '/home'         }     },      /* 组件模块 */     {         path: '/components',         key: '/components',         redirect: '/components/table/allTable', // 一级路由重定向         element: <Blank />,         meta: {             icon: <IconCommand />,             name: 'layout__main-menu__component',             title: '组件示例',             isAuth: true,             isHidden: false         },         children: [             {                 path: 'table',                 key: '/components/table',                 element: <Blank />,                 meta: {                     icon: 've-icon-table',                     name: 'layout__main-menu__component-table',                     title: '表格',                     isAuth: true                 },                 children: [                     {                         path: 'allTable',                         key: '/components/table/allTable',                         element: <Layout>{lazyload(lazy(() => import('@views/components/table/all')))}</Layout>,                         meta: {                             name: 'layout__main-menu__component-table_all',                             title: '所有表格'                         }                     },                     {                         path: 'customTable',                         key: '/components/table/customTable',                         element: <Layout>{lazyload(lazy(() => import('@views/components/table/custom')))}</Layout>,                         meta: {                             name: 'layout__main-menu__component-table_custom',                             title: '自定义表格'                         }                     },                     {                         path: 'search',                         key: '/components/table/search',                         element: <Blank />,                         meta: {                             name: 'layout__main-menu__component-table_search',                             title: '搜索'                         },                         children: [                             {                                 path: 'searchList',                                 key: '/components/table/search/searchList',                                 element: <Layout>{lazyload(lazy(() => import('@views/components/table/search')))}</Layout>,                                 meta: {                                     name: 'layout__main-menu__component-table_search_list',                                     title: '搜索列表'                                 }                             }                         ]                     }                 ]             },             {                 path: 'list',                 key: '/components/list',                 element: <Layout>{lazyload(lazy(() => import('@views/components/list')))}</Layout>,                 meta: {                     icon: 've-icon-order-o',                     name: 'layout__main-menu__component-list',                     title: '列表'                 }             },             {                 path: 'form',                 key: '/components/form',                 element: <Blank />,                 meta: {                     icon: 've-icon-exception',                     name: 'layout__main-menu__component-form',                     title: '表单',                     isAuth: true                 },                 children: [                     {                         path: 'allForm',                         key: '/components/form/allForm',                         element: <Layout>{lazyload(lazy(() => import('@views/components/form/all')))}</Layout>,                         meta: {                             name: 'layout__main-menu__component-form_all',                             title: '所有表单'                         }                     },                     {                         path: 'customForm',                         key: '/components/form/customForm',                         element: <Layout>{lazyload(lazy(() => import('@views/components/form/custom')))}</Layout>,                         meta: {                             name: 'layout__main-menu__component-form_custom',                             title: '自定义表单'                         }                     }                 ]             },             {                 path: 'markdown',                 key: '/components/markdown',                 element: <Layout>{lazyload(lazy(() => import('@views/components/markdown')))}</Layout>,                 meta: {                     icon: <IconUnorderedList />,                     name: 'layout__main-menu__component-markdown',                     title: 'markdown编辑器'                 }             },             {                 path: 'qrcode',                 key: '/components/qrcode',                 meta: {                     icon: 've-icon-qrcode',                     name: 'layout__main-menu__component-qrcode',                     title: '二维码'                 }             },             {                 path: 'print',                 key: '/components/print',                 meta: {                     icon: 've-icon-printer',                     name: 'layout__main-menu__component-print',                     title: '打印'                 }             },             {                 path: 'pdf',                 key: '/components/pdf',                 meta: {                     icon: 've-icon-pdffile',                     name: 'layout__main-menu__component-pdf',                     title: 'pdf'                 }             }         ]     },      /* 用户管理模块 */     {         path: '/user',         key: '/user',         redirect: '/user/userManage',         element: <Blank />,         meta: {             // icon: 've-icon-team',             icon: <IconUserGroup />,             name: 'layout__main-menu__user',             title: '用户管理',             isAuth: true,             isHidden: false         },         children: [             ...         ]     },      /* 配置模块 */     {         path: '/setting',         key: '/setting',         redirect: '/setting/system/website',         element: <Blank />,         meta: {             icon: 've-icon-settings-o',             name: 'layout__main-menu__setting',             title: '设置',             isHidden: false         },         children: [             ...         ]     },      /* 权限模块 */     {         path: '/permission',         key: '/permission',         redirect: '/permission/admin',         element: <Blank />,         meta: {             // icon: 've-icon-unlock',             icon: <IconLock />,             name: 'layout__main-menu__permission',             title: '权限管理',             isAuth: true,             isHidden: false         },         children: [             ...         ]     } ]

DeskMenu.jsx模板

/**  * Desk桌面多层级路由菜单  * 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-MacOS桌面管理系统|electron27+react仿mac桌面

OK,以上就是Electron27+React18开发仿制MacOS桌面系统的一些分享,希望对大家有些帮助哈~~

最后附上两个最近实例项目

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

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

Electron-React18-MacOS桌面管理系统|electron27+react仿mac桌面