React-Admin后台管理模板|react18+arco+zustand后台解决方案

基于react18.x+vite4+arco-design自研中后台管理系统解决方案ReactAdmin

react-vite-admin 基于vite4搭建react18.x后台管理项目。使用了react18 hooks+arco.design+zustand+bizcharts等技术实现权限管理模板框架。支持暗黑/亮色主题、i18n国际化、动态权限鉴定、3种布局模板、tab路由标签栏等功能。

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React18Admin管理系统是首创自研的轻量级中后台框架,构建运行速度快,支持dark/light主题模式。

React-Admin后台管理模板|react18+arco+zustand后台解决方案

技术栈

  • 编辑器:Vscode

  • 框架技术:react18+vite4+react-router+zustand+axios

  • 组件库:arco-design (字节前端react组件库)

  • 路由管理:react-router-dom^6.16.0

  • 状态管理:zustand^4.4.1

  • 模拟数据:mockjs^1.1.0

  • 模拟请求:axios^1.5.1

  • 图表库:bizcharts^4.1.22

  • 编辑器组件:@wangeditor/editor-for-react^1.0.6

  • markdown编辑器:@uiw/react-md-editor^3.23.6

  • 请求进度插件:nprogress^0.2.0

React-Admin后台管理模板|react18+arco+zustand后台解决方案

react-admin采用字节出品的react桌面端组件库arco.design

React-Admin后台管理模板|react18+arco+zustand后台解决方案

特性

  1. 基于vite4.x构建react18后台,轻/快/小

  2. 使用最新前端技术栈react18、zustand、bizcharts、react-router、axios

  3. 搭配清新react组件库arco.design

  4. 支持中英文/繁体国际化语言

  5. 支持动态路由权限验证

  6. 支持动态tabs标签栏控制

  7. 内置多种模板布局样式

React-Admin后台管理模板|react18+arco+zustand后台解决方案

项目结构目录

采用标准化的react目录结构,整个项目使用react18 function语法编码开发。

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

构建预览图

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

wangeditor-react图文编辑器使用的是wangeditor的react版本,支持dark/light主题。

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

react-md-editor基于reactmarkdown编辑器,支持dark/light主题。

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

react18-scrollbar项目中使用的虚拟滚动条基于react18自定义组件实现功能。

React-Admin后台管理模板|react18+arco+zustand后台解决方案

// 引入滚动条组件
import RScroll from '@/components/rscroll'<RScroll autohide maxHeight={100}>包裹需要滚动的内容块。。。</RScroll>

React18-Admin布局模板

React-Admin后台管理模板|react18+arco+zustand后台解决方案

如上图:支持分栏+垂直+水平3种通用布局模板。也可以定制化模板样式。

React-Admin后台管理模板|react18+arco+zustand后台解决方案

/**
 * 主布局模板
 * @author Hs Q:282310962*/import { useMemo } from 'react'import { appStore } from '@/store/app'import Columns from './template/columns'import Vertical from './template/vertical'import Transverse from './template/transverse'function Layout() {
    const { config: { skin,layout } } = appStore()// 布局模板const LayoutComponent = useMemo(() => {switch(layout) {case 'columns':return Columnscase 'vertical' Verticalcase 'transverse' Transversedefault Columns
        }
    },[layout])     (<div classname="radmin__container">
            <LayoutComponent />
        </div>    )
}

export default Layout

主模板Main.jsx动态Permission鉴权验证。

import './index.scss'import { Outlet } from 'react-router-dom'import RScroll from '@/components/rscroll'import Permission from '@/components/Permission'import Forbidden from '@/views/error/forbidden'import { useRoute } from '@/hooks/useRoutes'export default  Main() {
    const route = useRoute() (<>
            <RScroll>
                <div classname="ra__layout-main__wrapper">{ 鉴权组件 }<Permission
                        roles={route?.meta?.roles}
                        content={<Forbidden />}
                    >
                        <Outlet />
                    </Permission>
                </div>
            </RScroll>
        </>    )
}

react-router路由配置

React-Admin后台管理模板|react18+arco+zustand后台解决方案

*
 * @title    react-router-dom v6路由配置管理
 * @author    andyimport { useRoutes,Navigate } from 'react-router-dom'import Error from '@views/error/404' 批量导入modules路由const modules = import.meta.glob('./modules/*.jsx',{ eager: true })
const patchRoutes = Object.keys(modules).map(key => modules[key].).flat() useRoutes集中式路由配置export const routes = [
    {
        path: '/',element: <Navigate to="/home" replace={true} />,        meta: {
            isWhite: true  路由白名单        }
    },...patchRoutes, 404模块 path="*"不能省略    {
        path: '*'}
    }
]

const Router = () => useRoutes(routes)

export default Router

lazyload.jsx配置

*
 * 延迟加载提示import { Suspense } from 'react'import { Spin } from '@arco-design/web-react'import NprogressLoading from './nprogress' 加载提示const SpinLoading = () => { (<Spin
            tip='loading...'style={{
                width: '100%'}}/>    )
} 延迟加载const lazyload = LazyComponent => React 16.6 新增了<Suspense>组件,懒加载的模式需要我们给他加上一层 Loading的提示加载组件 return <Suspense fallback={<SpinLoading />}><LazyComponent /></Suspense>return <Suspense fallback={<NprogressLoading />}><LazyComponent /></Suspense>}

export default lazyload

NProgress.jsx配置

*
 * 加载进度条NProgressimport { Component } from 'react'import NProgress from 'nprogress'import 'nprogress/nprogress.css' class NprogressLoading extends Component {
    constructor(props) {
        super(props)
        NProgress.set(.4)
        NProgress.start()
    }

    componentDidmount() {
        NProgress.done()
    }

    render() {return <div />    }
}

主路由main.jsx配置

*
 * 主路由配置
 * @author Hsimport { lazy } from 'react'import {
    IconHome,IconDashboard,IconLink,IconCommand,IconUserGroup,IconLock,Iconmenu,IconSafe,IconBug,IconHighlight,IconUnorderedList,IconStop
} from '@arco-design/web-react/icon'import Layout from '@/layouts'import Blank from '@/layouts/blank'import lazyload from '../lazyload' [首页模块{
        path: '/home' 用于Menu组件跳转路由地址element: <Layout />,1)">        meta: { icon: 've-icon-home',// 菜单图标icon: <IconHome />,name: 'layout__main-menu__home',1)"> i18n国际化标题title: '主页' 需要鉴权isHidden: false,1)"> 是否隐藏菜单isAffix:  固定tabview标签栏(不可关闭)        },children: [
            {
                key: '/home'<span style="color: rgba(0,index: <span style="color: rgba(0,element: lazyload(lazy(() => import('@views/home'))),meta: {<span style="color: rgba(0,icon: <IconHome />,name: 'layout__main-menu__home-index' 工作台            {
                path: 'dashboard'<span style="color: rgba(0,key: '/home/dashboard'<span style="color: rgba(0,element: lazyload(lazy(() => import('@views/home/dashboard' icon: 've-icon-computer',icon: <IconDashboard />,name: 'layout__main-menu__home-workplace'<span style="color: rgba(0,title: '工作台' 外部链接            {
                path: 'https://react.dev/'<span style="color: rgba(0,key: 'https://react.dev/' icon: 've-icon-clip',icon: <IconLink />,name: 'layout__main-menu__home-apidocs'<span style="color: rgba(0,title: 'react.js官方文档'组件模块{
        ...
    },1)">用户管理模块权限模块错误模块{
        ...
    }
]

备注:路由菜单参数配置说明。

*
 * @description 路由参数说明
 * @param path ==> 路由地址标识
 * @param key ==> 用于Menu组件跳转路由地址
 * @param redirect ==> 重定向地址
 * @param element ==> 视图页面路径
 * 菜单信息(meta)
 *         @param meta.icon ==> 菜单图标
 *         @param meta.title ==> 菜单标题
 *         @param meta.name ==> i18n国际化标题
 *         @param meta.roles ==> 页面权限 ['admin','dev','test']
 *         @param meta.isAuth ==> 是否需要验证
 *         @param meta.isHidden ==> 是否隐藏页面
 *         @param meta.isAffix ==> 是否固定标签(tabs标签栏不能关闭)
 * */

react自定义路由菜单Menu

基于arco.design组件库提供的Menu组件封装三种不同的路由菜单。

React-Admin后台管理模板|react18+arco+zustand后台解决方案

  

React-Admin后台管理模板|react18+arco+zustand后台解决方案

React-Admin后台管理模板|react18+arco+zustand后台解决方案

RouteMenu />RouteMenu rootRouteEnable rootRouteEnable mode="horizontal" />

RouteMenu路由菜单模板

/**
 * 路由菜单模板
*/

import './index.scss'
import { useState,useMemo,useEffect } from 'react'
import { useNavigate,useLocation } from 'react-router-dom'
import { Menu } from '@arco-design/web-react'
import Icon from '@components/Icon'
import RouteSubMenu from './submenu'
import { routes } from '@/routers'
import { getcurrentRootRoute,findParentRoute } from '@/hooks/useRoutes'
import Locales from '@/locales'

export default function RouteMenu(props) {
    const {
        // 菜单类型(垂直vertical 水平菜单horizontal 弹出pop)
        mode = 'vertical',// 菜单风格('light' | 'dark')
        theme = 'light',// 是否开启一级路由菜单
        rootRouteEnable = false,style = {}
    } = props

    const navigate = useNavigate()
    const { pathname } = useLocation()
    const t = Locales()
    const [openKeys,setOpenKeys] = useState([])
    const rootRoute = getcurrentRootRoute()
    const filterRoutes = routes.filter(item => !item?.meta?.isWhite)

    const menuRoutes = useMemo(() => {
        if(rootRouteEnable) {
            return filterRoutes
        }
        // 过滤一级菜单
        return filterRoutes.find(item => item.path == rootRoute && item.children)?.children
    },[pathname])

    useEffect(() => {
        setOpenKeys(getKeys(pathname))
    },[pathname])

    // 获取选中菜单路由keys数组
    const getKeys = (key) => {
        return findParentRoute(menuRoutes,key)?.map(item => item?.key)
    }

    const handleNavigate = (key) => {
        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 {
            navigate(key)
        }
    }

    return (Menuclassname="ra__menus"mode={mode}theme={theme}selectedKeys={[pathname]}openKeys={openKeys}levelIndent={28}style={{ ...style }}
            onClickMenuItem={handleNavigate}onClickSubMenu={(_,openKeys) = {
                setOpenKeys(openKeys)
            }}
        >
            { menuRoutes.map(item => {
                if(item?.children) {
                    return RouteSubMenu(item,t)
                }
                return (
                    !item?.meta?.isHidden &&Menu.Item classname="ra__menuItem" key={item.redirect || item.key}{ item?.meta?.icon && Icon name={item.meta.icon} size={18} ={{marginRight: 10}} /> }
                        { item?.meta?.name && span>{t[item.meta.name]} }Menu.Item)
            })}Menu)
}

react18状态管理zustand

React-Admin后台管理模板|react18+arco+zustand后台解决方案

Zustand新一代react状态管理工具,内置多种插件,支持persist本地存储服务。

*
 * react18状态管理库Zustand4,中间件persist本地持久化存储import { create } from 'zustand'import { persist,createJSONStorage } from 'zustand/middleware'import { generate,getRgbStr } from '@arco-design/color'export const appStore = create(
    persist(
        (set,get) => ({ 语言(中文zh-CN 英文en 繁体字zh-TW)lang: 'zh-CN' 角色类型 roles: ['admin'] / roles: ['admin','dev'] / roles: ['dev',test']roles: ["dev"],1)"> 配置信息            config: { 布局(分栏columns 纵向vertical 横向transverse)layout: 'columns' 模式(亮色light - 暗黑dark)mode: 'light' 主题色theme: '#3491FA' 是否折叠菜单collapsed: false 开启面包屑导航breadcrumb:  开启标签栏tabsview:  显示搜索showSearch:  显示全屏showFullscreen:  显示语言showLang:  显示公告showNotice:  显示底部showFooter: },1)"> 更新配置updateConfig: (key,value) => set({
                config: { ...get().config,[key]: value }
            }),1)"> 设置角色setRoles: (roles) => set({roles}),1)"> 设置多语言setLang: (lang) => set({lang}),1)"> 设置主题模式setMode: (mode) => {if(mode == 'dark') { 设置为暗黑主题document.body.setattribute('arco-theme','dark')
                }else { 恢复亮色主题document.body.removeAttribute('arco-theme')
                }
                get().updateConfig('mode' 设置主题样式setTheme: (theme) => {
                const colors = generate(theme,{ list:  })
                colors.map((item,index) => {
                    const rgbStr = getRgbStr(item)
                    document.body.style.setProperty(`--arcoblue-${index + 1}`,rgbStr)
                })
                get().updateConfig('theme'e)  handleclickMenuItem(key,e,item)}>="close" disabled={item?.meta?.isAffix}><="ve-icon-close" />{t['tabview__contextmenu-close']}>="closeLeft"={isFirstTab()}="ve-icon-prev" />{t['tabview__contextmenu-closeleft']}="closeRight"={isLastTab()}="ve-icon-next" />{t['tabview__contextmenu-closeright']}="closeOther"="ve-icon-reset" />{t['tabview__contextmenu-closeother']}="closeAll"="ve-icon-close-circle-o" />{t['tabview__contextmenu-closeall']}>}
                    onVisibleChange={visible=>handleOpenContextMenu(visible,item)}
                >span ="ra__tabsview-title" onClick={() = navigate(item?.redirect || item?.key)}>TabIcon path={item?.key} { t[item?.meta?.name] }}
        />
    ))}Tabs>
export  TabsView() {
    const { pathname } = useLocation()
    const navigate = useNavigate()
    const [selectedTab,setSelectedTab] = useState()
    const { config: { tabRoutes },updateConfig } = appStore()
    const route = useRoute()
    const t = Locales()

    useEffect(() => {
        addTabs()
    },[pathname]) 添加const addTabs = () => {
        const tabIndex = tabRoutes.findIndex(item => item?.key === pathname)
        let newTabs = tabRoutesif(tabIndex == -1) {
            newTabs.push(route)
        }
        newTabs.map(item => {
            item.isactive = falseif(item?.key === pathname) {
                item.isactive = }
        })
        updateConfig('tabRoutes'<span style="color: rgba(0,newTabs)
    } 删除const delTabs = (path) => path)
        let newTabs =if(tabIndex > -1) {
            newTabs.splice(tabIndex,1)
            updateConfig('tabRoutes'<span style="color: rgba(0,newTabs)
            updatetabs(newTabs)
        }
    } 删除左侧标签const delLeftTabs = (path) =>) {
            newTabs = newTabs.filter((item,i) => item?.meta?.isAffix || i >= tabIndex)
            updateConfig('tabRoutes' 删除右侧标签const delRightTabs = (path) =><span style="color: rgba(0,i) => item?.meta?.isAffix || i <= 删除其它const delOtherTabs = (path) => {
        let newTabs = tabRoutes.filter(item => item?.meta?.isAffix || item?.key === path)
        updateConfig('tabRoutes' {
        e.stopPropagation()
        const path = item?.key(key) {case 'close':
                delTabs(path)breakcase 'closeLeft':
                delLeftTabs(path)case 'closeRight':
                delRightTabs(path)case 'closeOther':
                delOtherTabs(path)case 'closeAll':
                delAllTabs()break}
    } (
        ...
    )
}

OK,以上就是react18+arco开发后台系统的一些分享,希望对大家有所帮助~ 💖

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

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

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

React-Admin后台管理模板|react18+arco+zustand后台解决方案

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件举报,一经查实,本站将立刻删除。

本文链接:https://www.f2er.com/3188630.html

大家都在看

  • 飞码LowCode前端技术系列:如何便捷快速验证实现投产及飞码探索

    本篇文章从数据中心,事件中心如何协议工作、不依赖环境对vue2.x、vue3.x都可以支持、投产页面问题定位三个方面进行分析。
    2023-11-16 博文
  • 如何优雅使用 vuex

    大纲 本文内容更多的是讲讲使用 vuex 的一些心得想法,所以大概会讲述下面这些点: Q1:我为什么会想使用 vuex 来管理数据状态交互? Q2:使用 vuex 框架有哪些缺点或者说副作用? Q3:我是如何在项目里使用 vuex 的? 初识 vuex 对于 vuex,有人喜欢,有人反感 喜欢的人觉
    2023-11-16 博文
  • 第三方组件及计算属性传参的问题解决方式

    1. 前言 唉,好想玩滋嘣。 2. 计算属性直接传参接收不到 表格数据某一列需要用的计算属性时,模板中使用计算属性 fullName 就会直接调用 fullName 函数,而在模板中 fullName(item) 相当于fullName()(item),此处为函数柯里化。 &lt;el-table-
    2023-11-16 博文
  • 记录--Vue3基于Grid布局简单实现一个瀑布流组件

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 在学习Grid布局之时,我发现其是CSS中的一种强大的布局方案,它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局,在刷某书和某宝首页时,我们发现其展示方式就是一种瀑布流,是一种流行的网站页面布局,视觉表……
    2023-11-16 博文
  • 用强数据类型保护你的表单数据-基于antd表单的类型约束

    接口数据类型与表单提交数据类型,在大多数情况下,大部分属性的类型是相同的,但很少能做到完全统一。我在之前的工作中经常为了方便,直接将接口数据类型复用为表单内数据类型,在遇到属性类型不一致的情况时会使用any强制忽略类型错误。后来经过自省与思考,这种工作模式会引起各种隐藏bug,一定有更……
    2023-11-16 博文
  • pinia的使用

    前言 最近新开了个项目,以前老项目都是vue2+vuex开发的,都说用vue3+pinia爽得多,那新项目就vue3+pinia吧。这里记录一下pinia的使用。 使用方法 安装pinia: npm i pinia main.js中引入pinia: //main.js import { create
    2023-11-16 博文
  • 记录--让我们来深入了解一下前端“三清”是什么

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前端“三清” 在前端开发中,我们经常听到关于“三清”的说法,即 window、document、Object。这三者分别代表了 BOM(浏览器对象模型)、DOM(文档对象模型)以及 JS 的顶层对象。在这个体系中,我们通过 JavaScr
    2023-11-16 博文
  • 记录--啊?Vue是有三种路由模式的?

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 众所周知,vue路由模式常见的有 history 和 hash 模式,但其实还有一种方式-abstract模式(了解一哈~) 别急,本文我们将重点逐步了解: 路由 + 几种路由模式 + 使用场景 + 思考 + freestyle 路由概念
    2023-11-16 博文