源码
说明:
我这里是用了一个做了一个小demo,用到了antd的菜单
课前准备
创建Page目录(放页面)以及router目录(放路由以及菜单)
步骤一
我这里先搞个菜单
// src/router/routes.tsx
import { MenuProps } from "antd";
type MenuItem = Required<MenuProps>["items"][number];
export function getItem(
label: React.ReactNode,
key: React.Key,
icon?: React.ReactNode,
children?: MenuItem[],
type?: "group"
): MenuItem {
return {
key,
icon,
children,
label,
type,
} as MenuItem;
}
// src/router/index.tsx
import { MenuProps } from "antd";
import { MailOutlined } from "@ant-design/icons";
import { getItem } from "./routes";
export const items: MenuProps["items"] = [
getItem("菜单", "sub1", <MailOutlined />, [
getItem("首页", "/home"),
getItem("关于", "/about"),
]),
];
// src/App.tsx
import { Menu } from "antd";
import { items } from "./router";
function App() {
const location = useLocation();
const navigator = useNavigate();
const MenuClickHandle = (e: any) => {
navigator(e.key);
};
return (
<div className="App">
<Menu
items={items}
selectedKeys={[`${location.pathname}`]}
style={{ width: 256 }}
defaultOpenKeys={["sub1"]}
mode="inline"
onClick={(e) => MenuClickHandle(e)}
/>
</div>
);
}
export default App;
这时候菜单已经完成了~~~~
步骤二
开始玩路由了(在原有代码基础上继续加)
先在路由文件里面定义,再到出口文件处理
// src/router/routes.tsx
import { MenuProps, Spin } from "antd";
import { RouteObject } from "react-router-dom";
import { FC, lazy, LazyExoticComponent, Suspense } from "react";
type MenuItem = Required<MenuProps>["items"][number];
export function getItem(
label: React.ReactNode,
key: React.Key,
icon?: React.ReactNode,
children?: MenuItem[],
type?: "group"
): MenuItem {
return {
key,
icon,
children,
label,
type,
} as MenuItem;
}
export const routes: Route[] = [
{
path: "/",
component: lazy(() => import("../pages/test")),
},
{
path: "/home",
component: lazy(() => import("../pages/home")),
},
{
path: "/about",
component: lazy(() => import("../pages/about")),
children: [
{
path: "mine",
component: lazy(() => import("../pages/mine")),
},
],
},
];
export interface Route<T = any>
extends Omit<RouteObject, "element" | "children"> {
component: LazyExoticComponent<FC<T>>;
children?: Route[];
}
export const withRoutes = (routes: Route[]): RouteObject[] => {
const result: RouteObject[] = [];
routes.forEach((item) => {
const { component: Comp, children, ...reset } = item;
const route = {
...reset,
element: (
<Suspense fallback={<Spin />}>
<Comp />
</Suspense>
),
...(Array.isArray(children) &&
children.length > 0 && {
children: withRoutes(children),
}),
};
result.push(route);
});
return result;
};
// src/router/index.tsx
import { MenuProps } from "antd";
import { MailOutlined } from "@ant-design/icons";
import { useRoutes } from "react-router-dom";
import { routes, withRoutes } from "./routes";
import { getItem } from "./routes";
export const items: MenuProps["items"] = [
getItem("菜单", "sub1", <MailOutlined />, [
getItem("首页", "/home"),
getItem("关于", "/about"),
]),
];
const Routes = () => useRoutes(withRoutes(routes));
export default Routes;
最后在App.tsx使用路由
import { useLocation, useNavigate } from "react-router-dom";
import { Menu } from "antd";
import { items } from "./router";
import Routes from "./router";
function App() {
const location = useLocation();
const navigator = useNavigate();
const MenuClickHandle = (e: any) => {
navigator(e.key);
};
return (
<div className="App">
<Menu
items={items}
selectedKeys={[`${location.pathname}`]}
style={{ width: 256 }}
// defaultSelectedKeys={[`${location.pathname}`]}
defaultOpenKeys={["sub1"]}
mode="inline"
onClick={(e) => MenuClickHandle(e)}
/>
<Routes></Routes>
</div>
);
}
export default App;
因为我在定义about路由的时候有给它子路由,所以我的about页面要加outlet标签,相当于vue里面的router-view标签
// src/pages/about.tsx
import React, { memo } from "react";
import { Outlet } from "react-router-dom";
const about = memo(() => {
return (
<div>
<h1>about</h1>
<Outlet></Outlet>
</div>
);
});
export default about;
就此就完成了,先附上主要部分的完整代码
主要的路由与菜单部分完整代码
// src/router/index.tsx
import { MenuProps } from "antd";
import { MailOutlined } from "@ant-design/icons";
import { useRoutes } from "react-router-dom";
import { routes, withRoutes } from "./routes";
import { getItem } from "./routes";
export const items: MenuProps["items"] = [
getItem("菜单", "sub1", <MailOutlined />, [
getItem("首页", "/home"),
getItem("关于", "/about"),
]),
];
const Routes = () => useRoutes(withRoutes(routes));
export default Routes;
// src/router/routes.tsx
import { MenuProps, Spin } from "antd";
import { RouteObject } from "react-router-dom";
import { FC, lazy, LazyExoticComponent, Suspense } from "react";
type MenuItem = Required<MenuProps>["items"][number];
export function getItem(
label: React.ReactNode,
key: React.Key,
icon?: React.ReactNode,
children?: MenuItem[],
type?: "group"
): MenuItem {
return {
key,
icon,
children,
label,
type,
} as MenuItem;
}
export const routes: Route[] = [
{
path: "/",
component: lazy(() => import("../pages/test")),
},
{
path: "/home",
component: lazy(() => import("../pages/home")),
},
{
path: "/about",
component: lazy(() => import("../pages/about")),
children: [
{
path: "mine",
component: lazy(() => import("../pages/mine")),
},
],
},
];
export interface Route<T = any>
extends Omit<RouteObject, "element" | "children"> {
component: LazyExoticComponent<FC<T>>;
children?: Route[];
}
export const withRoutes = (routes: Route[]): RouteObject[] => {
const result: RouteObject[] = [];
routes.forEach((item) => {
const { component: Comp, children, ...reset } = item;
const route = {
...reset,
element: (
<Suspense fallback={<Spin />}>
<Comp />
</Suspense>
),
...(Array.isArray(children) &&
children.length > 0 && {
children: withRoutes(children),
}),
};
result.push(route);
});
return result;
};