用React给XXL-JOB开发一个新皮肤(二):目录规划和路由初始化

目录

  • 一. 简述
  • 二. 目录规划
  • 三. Vite 配置
    • 3.1. 配置路径别名
    • 3.2. 配置 less
  • 四. 页面
    • 4.1. 入口文件
    • 4.2. 骨架文件
    • 4.3. 普通页面
  • 五. 路由配置
  • 六. 预览启动

一. 简述

上一篇文章我们介绍了项目初始化,此篇文章我们会先介绍下当前项目的目录规划,接着对vite 配置以便我们后续的开发,最后会根据 xxl-job 的页面创建我们项目的页面并配置路由信息。

二. 目录规划

一般来说前端项目可以分为下面几个部分:页面、路由、状态管理、静态资源、工具方法。结合我们的项目我调整了下项目的目录结构如下:

  • api:存放 api 定义
  • assets:存放静态文件
  • components:公共组件
  • hooks:公共的 React Hooks
  • pages:存放页面
  • router:路由信息
  • store:存放状态管理文件
  • types:定义的接口交互的接口
  • utils:常用的一些工具类
    在这里插入图片描述

如果有其他的目录结构设计,可以评论区交流!

三. Vite 配置

上面我们规划了项目的目录结构,接着我们配置下 vite

3.1. 配置路径别名

配置路径别名之后可以省去写冗长的相对路径。
在这里插入图片描述
我们只需要在vite.config.ts 中添加如下配置:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from "path";// https://vitejs.dev/config/
export default defineConfig({plugins: [react()],resolve: {alias: {"@": path.resolve(__dirname, "src"),"@assets": path.resolve(__dirname, "src/assets"),"@pages": path.resolve(__dirname, "src/pages"),"@store ": path.resolve(__dirname, "src/store"),"@images ": path.resolve(__dirname, "src/assets/images"),},}
})

另外还需要修改 tsconfig.json,否者引入路径会飘红。

{"compilerOptions": {..."baseUrl": ".","paths": {"@/*": ["src/*"]}},...
}

3.2. 配置 less

我们在项目中使用less 做样式管理,需要在vite.config.ts中配置如下:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from "path";// https://vitejs.dev/config/
export default defineConfig({... 忽略css: {preprocessorOptions: {less: {// 全局变量modifyVars: {},javascriptEnabled: true,},},},
})

后续我们在实现切换主题的功能的时候还会在配置这个地方,现在先放一放。

四. 页面

xxl-job 的任务调度中心有登录页面和管理页面组成,而管理页面也是我们常规管理系统的页面结构(结构如下)。
在这里插入图片描述
所以菜单栏、头部、尾部相当于管理页面的骨架,内容部分是需要切换路由动态展示的。做过管理系统的同学们应该很快就可以大体规划出页面模块。下面看一下我在pages 目录下定义的页面模块如下:

  • course:使用教程
  • dispatch:调度日志
  • exception:异常页面
  • executor:执行器管理
  • layout:页面骨架
  • login:登录页面
  • task:任务管理
  • user:用户管理
  • index.tsx:入口文件

日常开发建议:在定义模块目录的时候,最好见名知意,路由表也最好和模块名称对应(遇到 BUG可以最快的定位到问题页面)。主打一个不防御编程。

4.1. 入口文件

在 index.tsx 中,我们会配置引入定义的路由和 antd 的配置组件,内容如下:

import {ConfigProvider} from "antd";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import RouterSpace from "@/router";
import zhCN from "antd/lib/locale/zh_CN";
import routers = RouterSpace.routers;const Application = () => {return <ConfigProvider locale={zhCN}><RouterProvider router={createBrowserRouter(routers)} /></ConfigProvider>
}export default Application;

这里我们使用 ConfigProvider全局化配置:https://ant-design.antgroup.com/components/config-provider-cn,方便我们使用国际化和配置组件样式等,具体可以看文档。

其中<RouterProvider router={createBrowserRouter(routers)} />,是通过createBrowserRouter 创建一个路由表,然后通过RouterProvider向下传递。

这里需要注意下BrowerserRouterHashRouter的区别:

  • BrowerserRouter:利用H5 history API实现url地址改变,并通过 pushStatereplaceState 改变 URL,但不会触发浏览器的刷新。这使得单页应用程序可以像多页应用程序一样具有多个路由;虽然此路由更加自然、美观,但是刷新页面的时候请求服务器,可能会导致 404错误;
  • HashRouter:使用window.location.hash 属性和window.onhashchange事件。可以监听浏览器hash值得变化,去执行相应的Js切换网页。使用 URL 中的 hash#)部分来进行路由管理;正是因为路由信息是存储在 URL 的哈希部分,不会出发服务器请求,但是哈希符号,影响美观;

所以在正常项目中我们都是需要和服务端配置使用的,建议使用BrowerserRouter就可以,在一些涉及到登录认证、菜单权限的权限的时候BrowerserRouter会它的妙用。

4.2. 骨架文件

骨架文件是为了定义公共组件部分,并提取出动态组件部分,代码如下:

import {Link, Outlet} from "react-router-dom"const LayoutPage = () => {return <div>{/* 菜单 */}<div><Link to={'/xxl-job/report'}>运行报表</Link><br/><Link to={'/xxl-job/task'}>任务管理</Link><br/><Link to={'/xxl-job/dispatch'}>调度日志</Link><br/><Link to={'/xxl-job/executor'}>执行器分管理</Link><br/><Link to={'/xxl-job/user'}>用户管理</Link><br/><Link to={'/xxl-job/course'}>使用教程</Link><br/><Link to={'/login'}>退出登录</Link></div>{/* 内容 */}<div>{/* 头 */}<div></div>{/* 内容 */}<div><Outlet /></div></div></div>
}export default LayoutPage

Outlet 是一个用于渲染子路由的组件。它通常与 Route 配合使用,用于在父路由中指定子路由的渲染位置。Outlet 充当了子路由渲染的占位符,告诉 React Router 在当前组件中的哪里渲染子路由。

LinkReact Router 提供的组件之一,用于在应用中创建导航链接。它通常用于代替传统的 <a> 标签,提供了一种在单页面应用(SPA)中进行客户端路由导航的方式,而无需进行页面的完整刷新。

下一篇文章会介绍 css 组件如何使用。

4.3. 普通页面

除了骨架和入口文件,其他模块暂时都是简单的普通页面,如下图:
在这里插入图片描述
这些模块都如 task 目录下的 index.tsx 文件内容都是类似,内容如下:

const TaskPage = () => {return <div>任务管理</div>
}export default TaskPage;

这里需要注意函数名称的命名规则,在定义导出函数名称的时候,最好是模块 + Page,这样可以很好的区别其他组件和页面组件。

五. 路由配置

我们在入口文件中通过createBrowserRouter(routers)创建路由表,这里面的 routers 就是我们需要定义的路由表结构信息。

import {Navigate, RouteObject} from "react-router-dom";
import LoginPage from "@/pages/login";
import TaskPage from "@/pages/task";
import ReportPage from "@/pages/report";
import DispatchPage from "@/pages/dispatch";
import ExecutorPage from "@/pages/executor";
import UserPage from "@/pages/user";
import CoursePage from "@/pages/course";
import LayoutPage from "@/pages/layout";
import NotFoundPage from "@/pages/exception/404.tsx";namespace RouterSpace {export const routers: RouteObject[] = [{ path: '/login', element: <LoginPage /> },{path: '/xxl-job',element: <LayoutPage />,children: [{ path: 'report', element: <ReportPage /> },{ path: 'task', element: <TaskPage /> },{ path: 'dispatch', element: <DispatchPage /> },{ path: 'executor', element: <ExecutorPage /> },{ path: 'user', element: <UserPage /> },{ path: 'course', element: <CoursePage /> },{ path: '404', element: <NotFoundPage /> },{ path: "*", element: <Navigate to={'/xxl-job/404'} /> }]},]
}export default RouterSpace;

后面我们会优化这块路由表,改为 lazy 加载。

这里我们需要注意下RouteObject,现阶段我们只使用了 pathelementchildren 三个属性,这里面还有很多重要的属性可以参看文档:https://reactrouter.com/en/main/route/route#type-declaration。

interface RouteObject {path?: string; // 指定路由的路径index?: boolean; // 默认子路由ßßchildren?: React.ReactNode; // 定义子路由,是一个包含其他RouteObject的数组。子路由的路径会相对于父路由的路径。caseSensitive?: boolean; // 表示路由是否区分大小写,默认为falseid?: string; // 为路由指定唯一的标识符loader?: LoaderFunction; // 一个异步加载函数,用于动态加载路由组件。鉴权的时候使用action?: ActionFunction; // 定义路由的生命周期函数,用于在路由渲染前或渲染后执行一些操作element?: React.ReactNode | null; // 指定路由匹配时要渲染的 React 元素hydrateFallbackElement?: React.ReactNode | null;errorElement?: React.ReactNode | null; // 在发生错误时渲染的元素Component?: React.ComponentType | null;HydrateFallback?: React.ComponentType | null;ErrorBoundary?: React.ComponentType | null;handle?: RouteObject["handle"];shouldRevalidate?: ShouldRevalidateFunction; // 一个函数,用于定义路由是否应该重新验证lazy?: LazyRouteFunction<RouteObject>; // 用于懒加载路由的函数
}

其他属性的使用可以参考我的另一个开源项目:https://gitee.com/molonglove/go-react-admin.git,里面有关于动态路由、权限等与路由相关的使用。

这里还有注意点:{ path: "*", element: <Navigate to={'/xxl-job/404'} /> },这个路由定义需要放在最后,意味着如果路由匹配失败会跳转的路由地址。

六. 预览启动

执行 yarn dev查看执行效果,就可以看到如下的效果!
在这里插入图片描述
下一篇文章我们将介绍借助 antd 实现登录页面和管理页面的Layout骨架。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Magics 教程

文章目录 基本流程基本操作页面的介绍基本操作 基本流程 基本操作 页面的介绍 右侧是工具页&#xff0c;可以直接进行调整&#xff0c;也可以在选项&帮助->自定义用户界面 那里进行相关的调整 基本操作 直接拖动鼠标左键&#xff1a;选中物体鼠标右键&#xff1a; 长按…

JVM工作原理与实战(十二):打破双亲委派机制-自定义类加载器

专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、打破双亲委派机制的方法 二、自定义类加载器 1.Tomcat自定义类加载器案例 2.自定义类加载器详解 3.案例解析 总结 前言 JVM作为Java程序的运行环境&#xff0c;其负责解释和执…

RAG:让大语言模型拥有特定的专属知识

作为一个在Chatbot领域摸爬滚打了7年的从业者&#xff0c;笔者可以诚实地说&#xff0c;在大语言模型的推动下&#xff0c;检索增强生成&#xff08;Retrieval Augmented Generation&#xff0c;RAG&#xff09;技术正在快速崛起。 RAG的搜索请求和生成式AI技术&#xff0c;为搜…

【教学类-45-06】正确 X-Y之间的三连加减题混合 (竖向排列)(44格:11题“++ ”11题“--”11题“ +-”11题“ -+” )

作品展示&#xff1a; 背景需求&#xff1a; 把以下四款3连题 混在一起&#xff0c;每种题目随机抽取11题&#xff0c;一共44格 出现问题&#xff1a; 1、- 、-里面有重复题 2、升序排列最好竖排展示 素材准备: ​ ​ 问题改正 1、单元格修改&#xff1a;确保竖列写入 …

【Docker项目实战】使用Docker部署nullboard任务管理工具

【Docker项目实战】使用Docker部署nullboard任务管理工具 一、nullboard介绍1.1 nullboard简介1.2 任务看板工具介绍 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍2.3 注意事项 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四…

C# WPF 数据绑定

需求 后台变量发生改变,前端对应的相关属性值也发生改变 实现 接口 INotifyPropertyChanged 用于通知客户端(通常绑定客户端)属性值已更改。 示例 示例一 官方示例代码如下 using System; using System.Collections.Generic; using System.ComponentModel; using Sys…

spring boot + mybatis + websocket + js实战

项目技术&#xff1a;spring boot mybatis websocket js 需求背景&#xff1a;当添加一个女孩时&#xff0c;页面的socket收到消息&#xff0c;打印最新的所有女生list&#xff0c;这样可以进一步在react/vue前端框架下&#xff0c;实现当A用户新增了某业务数据后&#xff…

迅为RK3568开发板Android11/12/Linux编译驱动到内核

在平时的驱动开发中&#xff0c;经常需要在内核中配置某种功能&#xff0c;为了方便大家开发和学习&#xff0c;本小 节讲解如何在内核中添加驱动。具体的讲解原理讲解请参考本手册的驱动教程。 Android11 源码如果想要修改内核&#xff0c;可以运行以下命令进行修改: cd ke…

ffmpeg 视频分辨率修改 质量压缩

随着手机像素的提高&#xff0c;拍摄视频也越来越大&#xff0c;10秒的视频动辄 二三十兆&#xff0c;这给视频传输和播放都带来了 诸多不变。一般都需要 前端或或者后端 对视频进行压缩。由于我这边前端是 H5&#xff0c;所以只能后端进行压缩&#xff0c; 采用主流压缩库采用…

centOS系统yum安装和卸载mongodb

0.1 什么是mongodb&#xff1f; 0.2 Mongodb是一个基于分布式文件存储的数据库。由C语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。 0.3 Mongodb是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当中功能最丰富&#xff0c;最像关系数据…

现代密码学 考点复盘

现代密码学 考点汇总&#xff08;上&#xff09; 写在最前面考试范围一、给一个简单的方案&#xff0c;判断是否cca安全二、随机预言机模型之下的简单应用 考试题目1.证明CBC方案是CPA安全的2. 证明哈希函数的抗碰撞性3. CBC-MAC安全&#xff1a;证明CPA安全的对称密钥加密方案…

使用git submodule解决高耦合度问题

引言 在开发我的笔记系统时&#xff0c;我遇到了一个问题。问题是&#xff0c;在api-gate服务中&#xff0c;我需要验证用户的access_code&#xff0c;但是access_code的生成逻辑是在auth2服务中实现的。这个问题从架构设计的层面上看&#xff0c;就是一个高耦合度问题。高耦合…

大数据 - Doris系列《三》- 数据表设计之表的基本概念

目录 &#x1f436;3.1 字段类型 &#x1f436;3.2 表的基本概念 3.2.1 Row & Column 3.2.2 分区与分桶 &#x1f959;3.2.2.1 Partition 1. Range 分区 2. List 分区 进阶&#xff1a;复合分区与单分区的选择 3.2.3 PROPERTIES &#x1f959;3.2.3.1 分片副本数 &#x1f…

正则表达式、文件访问(Python实现)

一、主要目的&#xff1a; 1.了解正则表达式的基本概念和处理过程。 2.掌握使用正则表达式模块 Re 进行字符串处理的方法。 3.了解文件的基本概念和类型。 4.掌握在 Python 中访问文本文件的方法和步骤。 5.熟悉在 Python 中访问二进制文件的方法和步骤。 二、主要内容和结…

【小白专用】C# 连接 MySQL 数据库

C# – Mysql 数据库连接 1. 配置环境 #前提&#xff1a;电脑已安装Mysql服务&#xff1b; Visual Studio 安装Mysql依赖库&#xff1a; 工具 -> NuGet 包管理器 -> 管理解决方案的 NuGet程序包 —> 搜索&#xff0c; 安装Mysql.Data (Oracle); (安装成功后&…

常用的网站

PIXEL MOTION 注册-YesPMP平台 模型下载 - Ourblender - 专业的三维素材库 Vega AI 创作平台 夏沫的AI小站 Tripo AI B站视频下载工具 | 极简纯净

视频监控录像服务器(中心录像服务器)功能详细介绍

目 录 一、概述 &#xff08;一&#xff09;定义 &#xff08;二&#xff09;视频监控中心录像服务器 二、存储策略服务 &#xff08;一&#xff09;存储策略配置 1、 录入页面 2、 选择需要进行录像的视频 3、批量选择多个通道号 4、其他关键参数…

rime中州韵小狼毫 敏感词脱敏滤镜

快速录入&#xff0c;是任何一个输入法&#xff0c;以及输入人员&#xff08;无论是否专业&#xff09;的追求目标之一。现实中&#xff0c;由于各种输入法在录入文本时&#xff0c;都无法完全避免重码的问题&#xff0c;所以在输入过程中都或多或少的需要进行选字/选词操作。这…

Redis不同环境缓存同一条数据,数据内部值不同

背景 现实中&#xff0c;本地环境&#xff08;dev&#xff09;和开发环境&#xff08;feature&#xff09;会共同使用相同的中间件&#xff08;本篇拿Redis举例&#xff09;&#xff0c;对于不同环境中的&#xff0c;图片、视频、语音等资源类型的预览地址url&#xff0c;需要配…

【C#】使用 LINQ 中的 Skip() 和 Take()进行分页,为什么要分页,分页作用是什么

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是是《C#》序列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握…