<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

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

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

      electron-react-macOs 基于electron27.x+vite4+react18+arcoDesign+zustand等技術構建桌面版仿MacOs框架系統解決方案。支持中英文/繁體、dark+light主題、桌面多層級路由、多窗口路由頁面、動態換膚、Dock懸浮菜單等功能。

      ElectronReactOS系統是首創自研的桌面多層級路由菜單、支持electron多開窗口+彈窗路由窗口

      技術棧

      • 開發工具: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虛擬滾動條組件)

      特性

      1. 桌面路由頁面支持暗黑+亮色模式
      2. 內置中英文/繁體國際化
      3. 經典桌面Dock懸浮菜單
      4. 可拖拽桌面路由+程序塢Dock菜單
      5. 桌面路由支持多個子級路由配置
      6. 動態視覺效果,自定義桌面換膚背景
      7. 可視化多窗口路由,支持electron新開窗口+rdialog彈窗頁面

      大家如果對Electron封裝多窗口感興趣,可以去看看下面這篇分享文章。

      http://www.rzrgm.cn/xiaoyan2017/p/17788495.html

      項目結構

      使用vite4構建react18項目,整合electron跨端技術,搭建桌面版OS管理系統。

      Electron桌面os布局模板

      桌面os布局分為頂部操作欄+桌面端路由菜單+底部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+React實現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+React桌面多級路由菜單

      如上圖:桌面菜單配置支持多級路由。

      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桌面多層級路由菜單
       * 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>
          )
      }

      OK,以上就是Electron27+React18開發仿制MacOS桌面系統的一些分享,希望對大家有些幫助哈~~

      最后附上兩個最新Electron+vue3實例項目

      Electron32-ViteOS桌面版os系統|vue3+electron+arco客戶端OS管理模板

      Electron31-Vue3Admin管理系統|vite5+electron+pinia桌面端后臺Exe

       

      posted @ 2023-11-23 00:16  xiaoyan2017  閱讀(915)  評論(1)    收藏  舉報
      友情鏈接: UP主小店B站
      主站蜘蛛池模板: 亚洲国产日韩欧美一区二区三区| 国产又爽又大又黄a片| 国产jlzzjlzz视频免费看| 国产一区二区三区怡红院| 成人3D动漫一区二区三区| 色av综合av综合无码网站| 人人爽天天碰天天躁夜夜躁| 国产精品推荐视频一区二区| 色 亚洲 日韩 国产 综合| 国产不卡av一区二区| 成av人片一区二区久久| 人成午夜免费大片| www插插插无码视频网站| 久久99久久99精品免视看国产成人| 热久久这里只有精品99| 亚洲国产另类久久久精品黑人| 久久精品国产中文字幕| 亚洲人成人网站色www| 玩弄漂亮少妇高潮白浆| 国产口爆吞精在线视频2020版| 久久热这里这里只有精品| 亚洲精品韩国一区二区| 一区二区三区成人| 116美女极品a级毛片 | 少妇被无套内谢免费看| 中文日产乱幕九区无线码| 精品午夜福利无人区乱码| 亚洲精品一二三在线观看| 无码人妻一区二区三区AV| 成人亚欧欧美激情在线观看| 极品蜜臀黄色在线观看| bt天堂新版中文在线| 久久久久香蕉国产线看观看伊| 伊人欧美在线| 好紧好湿好黄的视频| 精品国产免费一区二区三区香蕉 | 成人免费A级毛片无码片2022| 日本特黄特黄刺激大片| 国产精品十八禁在线观看| 高清无码爆乳潮喷在线观看| 欧美黑人又粗又大又爽免费|