1 通过yarn 模板创建reactjs项目
yarn create vite reactjs-antdesign-admin --template react-ts
2 基础路由测试
定义一个router/index.tsx,里面定义路由组件
const Router: React.FC = () => {
return (
<HashRouter>
<Switch>
<Route path="/" component={Welcome} exact/>
<Route path="/user" >
<Switch>
<Route path='/user' render={() => <Redirect to="/user/login" />} exact />
<Route path='/user/login' component={Login} />
</Switch>
</Route>
<Route path="/welcome"component={Welcome}/>
<Route path="/admin">
<Route path='/admin' render={() => <Redirect to="/admin/sub-page" />} exact />
<Route path='/admin/sub-page' component={Admin}/>
</Route>
<Route path="/list" component={TableList} />
<Route path="*" component={NotPage} />
</Switch>
</HashRouter>
);
};
在App.tsx中使用路由组件
function App() :ReactElement{
return (
<div className="App">
<BrowserRouter>
<Provider store={store}>
<Suspense fallback={<div>wwww</div>}>
<ErrorBoundary>
<Router />
</ErrorBoundary>
</Suspense>
</Provider>
</BrowserRouter>
</div>
);
}
export default App;
3 管理系统搭建
3.1 路由结构体
export interface AppRouter {
path: string //路由路径
name?: string //菜单名称
component?: //组件
| React.ComponentType<RouteComponentProps<any>>
| React.ComponentType<any>
auth?: boolean //是否认证
isHidden?: boolean //菜单是否隐藏
icon?: any //菜单图标
redirectUrl?: string //菜单是否重定向
routes?: AppRouter[] //子路由
}
3.2 路由定义
router/index.tsx
const routers: Array<AppRouter> = [
{
path: '/',
name: '主界面',
component: Welcome,
auth: true,
icon: <CrownFilled />,
},
{
path: '/user',
name: '用户管理',
redirectUrl: '/user/login',
isHidden: true,
icon: <CrownFilled />,
routes: [
{
path: '/user/login',
component: Login,
icon: <CrownFilled />,
},
],
},
{
name: '欢迎界面',
path: '/welcome',
component: Welcome,
icon: <CrownFilled />,
auth: true,
},
{
name: '管理员',
path: '/admin',
redirectUrl: '/admin/sub-page',
icon: <CrownFilled />,
routes: [
{
name: '管理子页',
path: '/admin/sub-page',
icon: <CrownFilled />,
component: Admin,
},
],
},
{
name: '列表页面',
path: '/list',
component: TableList,
icon: <CrownFilled />,
auth: true,
},
{
path: '*',
component: NotPage,
auth: true,
isHidden: true,
},
]
3.3 App布局文件
function App(): ReactElement {
return (
<>
<BrowserRouter>
<Provider store={store}>
<Suspense fallback={<PageLoading></PageLoading>}>
<ErrorBoundary>
<FrontendRouter routerConfig={WithAppRouters(routers)} />
</ErrorBoundary>
</Suspense>
</Provider>
</BrowserRouter>
</>
)
}
export default App
FontendRouter是处理认证的信息,WithAppRouters是重新构建真正的路由信息列表
FontendRouter主要是导入路由包含在
<MainLayout>
<Route
path={pathname}
component={targetRouterConfig.component}
exact
/>
</MainLayout>
3.4 MainLayout布局文件定义
这里直接去ProLayout - 高级布局 - ProComponents (ant.design) 选择需要的布局
const MainLayout: React.FC<{ children: ReactNode }> = (props) => {
const [settings, setSetting] = useState<Partial<ProSettings> | undefined>({
fixSiderbar: true,
layout: 'mix',
splitMenus: false,
})
const [pathname, setPathname] = useState('/')
const [num, setNum] = useState(40)
if (typeof document === 'undefined') {
return <div />
}
return (
<div
id="test-pro-layout"
style={{
height: '100vh',
overflow: 'auto',
}}
>
<ProConfigProvider hashed={false}>
<ConfigProvider
getTargetContainer={() => {
return document.getElementById('test-pro-layout') || document.body
}}
>
<ProLayout
prefixCls="my-prefix"
bgLayoutImgList={[
{
src: 'https://img.alicdn.com/imgextra/i2/O1CN01O4etvp1DvpFLKfuWq_!!6000000000279-2-tps-609-606.png',
left: 85,
bottom: 100,
height: '303px',
},
{
src: 'https://img.alicdn.com/imgextra/i2/O1CN01O4etvp1DvpFLKfuWq_!!6000000000279-2-tps-609-606.png',
bottom: -68,
right: -45,
height: '303px',
},
{
src: 'https://img.alicdn.com/imgextra/i3/O1CN018NxReL1shX85Yz6Cx_!!6000000005798-2-tps-884-496.png',
bottom: 0,
left: 0,
width: '331px',
},
]}
{...defaultProps}
location={{
pathname,
}}
token={{
header: {
colorBgMenuItemSelected: 'rgba(0,0,0,0.04)',
},
}}
avatarProps={{
src: 'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
size: 'small',
title: '七妮妮',
render: (props, dom) => {
return (
<Dropdown
menu={{
items: [
{
key: 'logout',
icon: <LogoutOutlined />,
label: '退出登录',
},
],
}}
>
{dom}
</Dropdown>
)
},
}}
actionsRender={(props) => {
if (props.isMobile) return []
if (typeof window === 'undefined') return []
return [
<InfoCircleFilled key="InfoCircleFilled" />,
<QuestionCircleFilled key="QuestionCircleFilled" />,
<GithubFilled key="GithubFilled" />,
]
}}
menuFooterRender={(props) => {
if (props?.collapsed) return undefined
return (
<div
style={{
textAlign: 'center',
paddingBlockStart: 12,
}}
>
<div>© 2021 Made with love</div>
<div>by Ant Design</div>
</div>
)
}}
onMenuHeaderClick={(e) => console.log(e)}
menuItemRender={(item, dom) => (
<div
onClick={() => {
setPathname(item.path || '/welcome')
}}
>
{dom}
</div>
)}
{...settings}
>
{props.children}
</ProLayout>
</ConfigProvider>
</ProConfigProvider>
</div>
)
}
export default MainLayout
prelayout需要配置:_defaultProps.tsx
import { CrownFilled } from '@ant-design/icons'
import { AppRouter } from '../FrontendAuth'
import { routers } from '@/router'
//将默认的路由配置生成prelayout需要的
export function WithAppRouters(appRouters1: AppRouter[]): AppRouter[] {
const appRouterFun = (appRouters2: AppRouter[]): AppRouter[] => {
const newAppRouters: AppRouter[] = []
for (const appRouter of appRouters2) {
if (!appRouter.isHidden) {
newAppRouters.push(appRouter)
if (appRouter.routes && appRouter.routes.length > 0) {
appRouter.routes = WithAppRouters(appRouter.routes)
}
}
}
return newAppRouters
}
return appRouterFun(appRouters1)
}
export default {
route: {
path: '/',
routes: WithAppRouters(routers),
},
location: {
pathname: '/',
},
}