react router v6总结

一、使用createBrowserRouter()创建路由:

  • 路由懒加载
  • 路由鉴权
  • 路由不存在则返回错误页面

1、src/router/index.tsx:

import React, { lazy } from "react";
import { createBrowserRouter } from "react-router-dom";
const ErrorPage = lazy(() => import("@/pages/404/"));
const Auth = lazy(() => import("@/components/auth"));

const router = createBrowserRouter([
  {
    path: "/",
    errorElement: <ErrorPage />,
    async lazy() {
      const { default: App } = await import("@/App");
      return { Component: App };
    },
    children: [
      {
        errorElement: <ErrorPage />,
        children: [
          {
            index: true,
            async lazy() {
              const { default: Home } = await import("@/pages/home/");
              return {
                element: (
                  <Auth>
                    <Home />
                  </Auth>
                )
              };
            }
          },
          {
            path: "collapse",
            async lazy() {
              const { default: Collapse } = await import("@/pages/collapse/");
              return {
                element: (
                  <Auth>
                    <Collapse />
                  </Auth>
                )
              };
            }
          },
          {
            path: "timeline",
            async lazy() {
              const { default: Timeline } = await import("@/pages/timeline/");
              return {
                element: (
                  <Auth>
                    <Timeline />
                  </Auth>
                )
              };
            }
          },
          {
            path: "app",
            async lazy() {
              const { default: Application } = await import(
                "@/pages/application/"
              );
              return {
                element: (
                  <Auth>
                    <Application />
                  </Auth>
                )
              };
            }
          }
        ]
      }
    ]
  },
  {
    path: "/login",
    async lazy() {
      const { default: Admin } = await import("@/pages/login/");
      return {
        element: (
          <Auth>
            <Admin />
          </Auth>
        )
      };
    }
  }
]);

export default router;

注意其中的index: true

          {
            index: true,
            async lazy() {
              const { default: Home } = await import("@/pages/home/");
              return {
                element: (
                  <Auth>
                    <Home />
                  </Auth>
                )
              };
            }
          }

2、src/index.tsx:

import React from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider } from "react-router-dom";
import router from "@/router";
import reportWebVitals from "@/reportWebVitals";
import "@/index.css";

const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);

root.render(<RouterProvider router={router} />);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

注意其中的:

<RouterProvider router={router} />

3、src/App.tsx:添加占位符<Outlet/>

import React from "react";
import { Layout } from "antd";
import Dropdown from "@/components/header/Dropdown";
import Search from "@/components/header/Search";
import SiderMenu from "@/components/sider-menu/";
import { Outlet } from "react-router-dom";
import { observer } from "mobx-react";
import mobxData from "@/store/mobx-data";
import "@/App.css";

const { Header, Content, Sider } = Layout;

const App: React.FC = () => {
  return (
    <Layout className="app-layout">
      <Header className="app-header">
        <div className="app-logo">
          <img height="36" src={require("@/logo.png")} />
        </div>

        <div className="search">
          <Search />
        </div>
        <Dropdown />
      </Header>
      <Layout className="app-wrapper">
        <Sider width={mobxData.width} className="app-sider">
          <SiderMenu />
        </Sider>
        <Layout className="app-wrapper-in">
          <Content className="app-content">
            <Outlet />
          </Content>
        </Layout>
      </Layout>
    </Layout>
  );
};

export default observer(App);

注意其中的:

<Outlet />

 4、src/sider-menu/index.tsx:添加导航NavLink

import React, { useState } from "react";
import { Button, Tooltip } from "antd";
import {
  HomeOutlined,
  FolderOutlined,
  AppstoreOutlined,
  ReadOutlined,
  TableOutlined,
  ProductOutlined,
  MenuFoldOutlined,
  MenuUnfoldOutlined
} from "@ant-design/icons";
import { NavLink } from "react-router-dom";
import mobxData from "@/store/mobx-data";
import "./index.css";

const App: React.FC = () => {
  const [status, setStatus] = useState(false);

  const onChangeWidth = () => {
    const elements = document.querySelectorAll(".menu-item dd") as NodeListOf<
      HTMLElement
    >;

    if (status) {
      mobxData.setWidth(90);

      for (let i = 0; i < elements.length; i++) {
        (elements[i].style as any).display = "block";
      }
    } else {
      mobxData.setWidth(60);

      for (let i = 0; i < elements.length; i++) {
        (elements[i].style as any).display = "none";
      }
    }

    setStatus(!status);
  };

  return (
    <div className="menu">
      <div className="menu-item-all">
        <NavLink to="/">
          <dl className="menu-item">
            <dt>
              {status ? (
                <Tooltip
                  placement="right"
                  title="我的门户"
                  className="menu-tooltip"
                >
                  <Button type="text" icon={<HomeOutlined />} />
                </Tooltip>
              ) : (
                <HomeOutlined />
              )}
            </dt>
            <dd>我的门户</dd>
          </dl>
        </NavLink>
        <NavLink to="/timeline">
          <dl className="menu-item">
            <dt>
              {status ? (
                <Tooltip
                  placement="right"
                  title="文档中心"
                  className="menu-tooltip"
                >
                  <Button type="text" icon={<FolderOutlined />} />
                </Tooltip>
              ) : (
                <FolderOutlined />
              )}
            </dt>
            <dd>文档中心</dd>
          </dl>
        </NavLink>
        <NavLink to="/collapse">
          <dl className="menu-item">
            <dt>
              {status ? (
                <Tooltip
                  placement="right"
                  title="工作中心"
                  className="menu-tooltip"
                >
                  <Button type="text" icon={<AppstoreOutlined />} />
                </Tooltip>
              ) : (
                <AppstoreOutlined />
              )}
            </dt>
            <dd>工作中心</dd>
          </dl>
        </NavLink>
        <dl className="menu-item">
          <dt>
            {status ? (
              <Tooltip
                placement="right"
                title="知识中心"
                className="menu-tooltip"
              >
                <Button type="text" icon={<ReadOutlined />} />
              </Tooltip>
            ) : (
              <ReadOutlined />
            )}
          </dt>
          <dd>知识中心</dd>
        </dl>
        <dl className="menu-item">
          <dt>
            {status ? (
              <Tooltip
                placement="right"
                title="表格中心"
                className="menu-tooltip"
              >
                <Button type="text" icon={<TableOutlined />} />
              </Tooltip>
            ) : (
              <TableOutlined />
            )}
          </dt>
          <dd>表格中心</dd>
        </dl>
        <NavLink to="/app">
          <dl className="menu-item">
            <dt>
              {status ? (
                <Tooltip
                  placement="right"
                  title="应用"
                  className="menu-tooltip"
                >
                  <Button type="text" icon={<ProductOutlined />} />
                </Tooltip>
              ) : (
                <ProductOutlined />
              )}
            </dt>
            <dd>应用</dd>
          </dl>
        </NavLink>
      </div>

      <div className="collapse">
        <Tooltip placement="right" title={status ? "展开" : "收起"}>
          <Button
            type="text"
            icon={
              status ? (
                <MenuUnfoldOutlined onClick={onChangeWidth} />
              ) : (
                <MenuFoldOutlined onClick={onChangeWidth} />
              )
            }
            onClick={onChangeWidth}
          />
        </Tooltip>
      </div>
    </div>
  );
};

export default App;

注意其中的NavLink及css中添加的active属性

.menu a.active {
    color: #126ee3;
    border-right: 3px solid #126ee3;
    background: #dddee2;
}

5、路由鉴权:src/components/auth/index.tsx

  • 直接输入登录页,如果没有登录则进入登录页;如果已经登录,则直接进入首页;
  • 输入子页,如果没有登录,则跳转至登录页;如果已经登录,则直接进入该页;
import React, { useEffect } from "react";
// import { useNavigate } from "react-router-dom";
import { useLocation, Navigate } from "react-router-dom";

interface Props {
  children: React.ReactElement;
}

export default function Auth({ children }: Props) {
  const { pathname } = useLocation();
  const isAuth = localStorage.getItem("token");

  if (pathname === "/login") {
    if (isAuth && Number(isAuth) !== 1) {
      return <Navigate to="/" />;
    } else {
      return <>{children}</>; // 写成:return <Navigate to="/login" />会造成无限循环
    }
  }

  if (isAuth && Number(isAuth) !== 1) {
    return <>{children}</>;
  } else {
    return <Navigate to="/login" />;
  }
}

6、src/pages/404/index.tsx:错误页面

import React from "react"
import {Button} from "antd"

const App: React.FC = () => {
    return <div>
        <p>404,当前页面不存在!</p>
        <div><Button type="primary" onClick={()=>window.history.back()}>返回</Button></div>
    </div>
}

export default App;

二、使用标签创建:

  • 路由懒加载
  • 路由鉴权
  • 路由不存在则返回错误页面

 1、src/index.tsx:

import React from "react";
import ReactDOM from "react-dom/client";
import reportWebVitals from "@/reportWebVitals";
import "@/index.css";
import BaseRouter from "@/routes"

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);

root.render(
  <BaseRouter/>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

2、 src/routes/index.tsx:路由配置文件

import React, { lazy, Suspense } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Auth from "@/components/auth/";

const App = lazy(() => import("@/App"));
const Home = lazy(() => import("@/pages/home/"));
const Collapse = lazy(() => import("@/pages/collapse/"));
const Timeline = lazy(() => import("@/pages/timeline/"));
const Application = lazy(() => import("@/pages/application/"));
const Login = lazy(() => import("@/pages/login/"));
const NotFound = lazy(() => import("@/pages/404/"));

const suspense = (Comp: JSX.Element) => (
  <Suspense fallback={<div>loading...</div>}>{Comp}</Suspense>
);

const BaseRouter = () => (
  <BrowserRouter>
    <Suspense fallback={<div>loading...</div>}>
      <Routes>
        <Route
          path="/"
          element={suspense(
            <Auth>
              <App />
            </Auth>
          )}
        >
          <Route index element={suspense(<Home />)}></Route>
          <Route path="collapse" element={suspense(<Collapse />)}></Route>
          <Route path="timeline" element={suspense(<Timeline />)}></Route>
          <Route path="app" element={suspense(<Application />)}></Route>
        </Route>
        <Route
          path="login"
          element={suspense(
            <Auth>
              <Login />
            </Auth>
          )}
        ></Route>
        <Route path="*" element={suspense(<NotFound />)}></Route>
      </Routes>
    </Suspense>
  </BrowserRouter>
);

export default BaseRouter;

3、src/App.tsx:首页,<Outlet/>为占位符

import React from "react";
import { Outlet } from "react-router-dom"
import { Layout } from "antd";
import Dropdown from "@/components/header/Dropdown";
import Search from "@/components/header/Search";
import SiderMenu from "@/components/sider-menu/";
import { observer } from "mobx-react";
import mobxData from "@/store/mobx-data";
import "@/App.css";

const { Header, Content, Sider } = Layout;

const App: React.FC = () => {

  return (
    <Layout className="app-layout">
      <Header className="app-header">
        <div className="app-logo">
          <img height="36" src={require("@/logo.png")} />
        </div>

        <div className="search">
          <Search />
        </div>
        <Dropdown />
      </Header>
      <Layout className="app-wrapper">
        <Sider width={mobxData.width} className="app-sider">
          <SiderMenu />
        </Sider>
        <Layout className="app-wrapper-in">
          <Content className="app-content">
            {/* {element} */}
            <Outlet/>
          </Content>
        </Layout>
      </Layout>
    </Layout>
  );
};

export default observer(App);

4、src/login/index.tsx:登录页

import React from "react";
import { useNavigate } from "react-router-dom";
import { Dropdown, Space, Button, Checkbox, Form, Input } from "antd";
import {
  DownloadOutlined,
  GlobalOutlined,
  DownOutlined,
  LockOutlined,
  UserOutlined
} from "@ant-design/icons";
import "./index.css";

const items1 = [
  {
    key: "1",
    label: "下载客户端"
  },
  {
    key: "2",
    label: "下载证书",
    children: [
      {
        key: "2-1",
        label: "下载应用证书"
      },
      {
        key: "2-2",
        label: "证书安装文档"
      }
    ]
  },
  {
    key: "3",
    label: "RESTFUL API"
  },
  {
    key: "4",
    label: "Web组件"
  }
];

const items2 = [
  {
    key: "5",
    label: "简体中文"
  },
  {
    key: "6",
    label: "繁体中文"
  },
  {
    key: "7",
    label: "ENGLISH"
  }
];

const App: React.FC = () => {
  let navigate = useNavigate();

  const onFinish = (values: string) => {
    console.log("Received values of form: ", values);
    localStorage.setItem("token", "2");
    navigate("/");
  };

  return (
    <div className="container">
      <div className="background-container"></div>
      <div className="wrapper">
        <div className="oem">
          <div className="oem-img"></div>
        </div>

        <div className="index">
          <div className="wrap-header-bar">
            <div className="app-index-bar" style={{ width: "504px" }}>
              <div
                className="app-index-bar-item"
                style={{ paddingRight: "16px" }}
              >
                <Dropdown
                  menu={{
                    items: items1
                  }}
                  trigger={["click"]}
                >
                  <a onClick={e => e.preventDefault()}>
                    <DownloadOutlined
                      style={{
                        fontSize: "14px",
                        cursor: "pointer",
                        marginRight: "5px"
                      }}
                    />
                    <Space>
                      下载
                      <DownOutlined />
                    </Space>
                  </a>
                </Dropdown>
              </div>
              <div className="app-index-bar-item">
                <Dropdown
                  menu={{
                    items: items2
                  }}
                  trigger={["click"]}
                >
                  <a onClick={e => e.preventDefault()}>
                    <GlobalOutlined
                      style={{
                        fontSize: "14px",
                        cursor: "pointer",
                        marginRight: "5px"
                      }}
                    />
                    <Space>
                      简体中文
                      <DownOutlined />
                    </Space>
                  </a>
                </Dropdown>
              </div>
            </div>
          </div>
          <div className="wrap-login">
            <div className="index-panel">
              <div className="logo-wrapper">
                <img
                  className="logo-image"
                  src={require("./images/logo.png")}
                />
              </div>
              <div className="title-wrapper">企业内容门户</div>
              <div className="signin-wrapper">
                <Form
                  name="normal_login"
                  className="login-form"
                  initialValues={{
                    remember: true
                  }}
                  onFinish={onFinish}
                >
                  <Form.Item
                    name="username"
                    rules={[
                      {
                        required: true,
                        message: "请输入账号!"
                      }
                    ]}
                  >
                    <Input
                      prefix={<UserOutlined className="site-form-item-icon" />}
                      placeholder="请输入账号"
                      className="login-form-input"
                    />
                  </Form.Item>
                  <Form.Item
                    name="password"
                    className="login-form-item"
                    rules={[
                      {
                        required: true,
                        message: "请输入密码!"
                      }
                    ]}
                  >
                    <Input
                      prefix={<LockOutlined className="site-form-item-icon" />}
                      type="password"
                      placeholder="请输入密码"
                      className="login-form-input"
                    />
                  </Form.Item>
                  <Form.Item>
                    <Form.Item name="remember" valuePropName="checked" noStyle>
                      <Checkbox>记住登录状态</Checkbox>
                    </Form.Item>
                  </Form.Item>

                  <Form.Item>
                    <Button
                      type="primary"
                      htmlType="submit"
                      className="login-form-button"
                    >
                      登 录
                    </Button>
                  </Form.Item>
                </Form>
              </div>
            </div>
          </div>
          <div className="wrap-footer">
            <div>
              <div className="login-view-all">
                登录即表示同意<a>用户协议</a>
                <span>、 </span>
                <span>
                  <a>隐私政策</a>
                </span>
              </div>
            </div>
            <div className="split"></div>
            <div className="app-index-about" style={{ marginTop: "0px" }}>
              <span className="version-information">版本信息</span>
              <div className="app-index-about-row">
                <span className="app-index-separator">&nbsp;I&nbsp;</span>
                <a
                  className="app-index-record"
                  href="http://beian.miit.gov.cn"
                  target="_blank"
                >
                  沪ICP备09089247号-9
                </a>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default App;

5、src/pages/404/index.tsx:错误页

import React from "react"
import {Button} from "antd"

const App: React.FC = () => {
    return <div>
        <p>404,当前页面不存在!</p>
        <div><Button type="primary" onClick={()=>window.history.back()}>返回</Button></div>
    </div>
}

export default App;

6、src/sider-menu/index.tsx:添加导航<NavLink></NavLink>

import React, { useState } from "react";
import { Button, Tooltip } from "antd";
import {
  HomeOutlined,
  FolderOutlined,
  AppstoreOutlined,
  ReadOutlined,
  TableOutlined,
  ProductOutlined,
  MenuFoldOutlined,
  MenuUnfoldOutlined
} from "@ant-design/icons";
import { NavLink } from "react-router-dom";
import mobxData from "@/store/mobx-data";
import "./index.css";

const App: React.FC = () => {
  const [status, setStatus] = useState(false);

  const onChangeWidth = () => {
    const elements = document.querySelectorAll(".menu-item dd") as NodeListOf<
      HTMLElement
    >;

    if (status) {
      mobxData.setWidth(90);

      for (let i = 0; i < elements.length; i++) {
        (elements[i].style as any).display = "block";
      }
    } else {
      mobxData.setWidth(60);

      for (let i = 0; i < elements.length; i++) {
        (elements[i].style as any).display = "none";
      }
    }

    setStatus(!status);
  };

  return (
    <div className="menu">
      <div className="menu-item-all">
        <NavLink to="/">
          <dl className="menu-item">
            <dt>
              {status ? (
                <Tooltip
                  placement="right"
                  title="我的门户"
                  className="menu-tooltip"
                >
                  <Button type="text" icon={<HomeOutlined />} />
                </Tooltip>
              ) : (
                <HomeOutlined />
              )}
            </dt>
            <dd>我的门户</dd>
          </dl>
        </NavLink>
        <NavLink to="/timeline">
          <dl className="menu-item">
            <dt>
              {status ? (
                <Tooltip
                  placement="right"
                  title="文档中心"
                  className="menu-tooltip"
                >
                  <Button type="text" icon={<FolderOutlined />} />
                </Tooltip>
              ) : (
                <FolderOutlined />
              )}
            </dt>
            <dd>文档中心</dd>
          </dl>
        </NavLink>
        <NavLink to="/collapse">
          <dl className="menu-item">
            <dt>
              {status ? (
                <Tooltip
                  placement="right"
                  title="工作中心"
                  className="menu-tooltip"
                >
                  <Button type="text" icon={<AppstoreOutlined />} />
                </Tooltip>
              ) : (
                <AppstoreOutlined />
              )}
            </dt>
            <dd>工作中心</dd>
          </dl>
        </NavLink>
        <dl className="menu-item">
          <dt>
            {status ? (
              <Tooltip
                placement="right"
                title="知识中心"
                className="menu-tooltip"
              >
                <Button type="text" icon={<ReadOutlined />} />
              </Tooltip>
            ) : (
              <ReadOutlined />
            )}
          </dt>
          <dd>知识中心</dd>
        </dl>
        <dl className="menu-item">
          <dt>
            {status ? (
              <Tooltip
                placement="right"
                title="表格中心"
                className="menu-tooltip"
              >
                <Button type="text" icon={<TableOutlined />} />
              </Tooltip>
            ) : (
              <TableOutlined />
            )}
          </dt>
          <dd>表格中心</dd>
        </dl>
        <NavLink to="/app">
          <dl className="menu-item">
            <dt>
              {status ? (
                <Tooltip
                  placement="right"
                  title="应用"
                  className="menu-tooltip"
                >
                  <Button type="text" icon={<ProductOutlined />} />
                </Tooltip>
              ) : (
                <ProductOutlined />
              )}
            </dt>
            <dd>应用</dd>
          </dl>
        </NavLink>
      </div>

      <div className="collapse">
        <Tooltip placement="right" title={status ? "展开" : "收起"}>
          <Button
            type="text"
            icon={
              status ? (
                <MenuUnfoldOutlined onClick={onChangeWidth} />
              ) : (
                <MenuFoldOutlined onClick={onChangeWidth} />
              )
            }
            onClick={onChangeWidth}
          />
        </Tooltip>
      </div>
    </div>
  );
};

export default App;

7、路由鉴权:src/components/auth/index.tsx

import React from "react";
// import { useNavigate } from "react-router-dom";
import { useLocation, Navigate } from "react-router-dom";

interface Props {
  children: React.ReactElement;
}

export default function Auth({ children }: Props) {
  const {pathname} = useLocation();
  const isAuth = localStorage.getItem("token");

  if (pathname === "/login") {
    if (isAuth && Number(isAuth) !== 1) {
      return <Navigate to="/" />;
    } else {
      return <>{children}</>; // 写成:return <Navigate to="/login" />会造成无限循环
    }
  }

  if (isAuth && Number(isAuth) !== 1) {
    return <>{children}</>;
  } else {
    return <Navigate to="/login" />;
  }
}

三、使用useRoutes()创建:

  • 路由懒加载
  • 路由鉴权
  • 路由不存在则返回错误页面

1、src/index.tsx:使用BrowserRouter

import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter} from "react-router-dom";
import reportWebVitals from "@/reportWebVitals";
import App from "./App";
import "@/index.css";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);

root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

reportWebVitals();

2、src/App.tsx:使用useRoutes()

使用<Suspense></Suspense>是为了防止在使用路由懒加载时报错。

import React, { Suspense } from "react";
import { useRoutes } from "react-router-dom"
import routes from "@/routes/"
import "@/App.css";

const App: React.FC = () => {
  const myRoutes = useRoutes(routes);

  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        {myRoutes}
      </Suspense>
    </div>
  );
};

export default App;

3、src/pages/Layout/index.tsx:首页,使用<Outlet />在其特定位置插入子页面

import React from "react";
import { Outlet } from "react-router-dom"
import { Layout } from "antd";
import Dropdown from "@/components/header/Dropdown";
import Search from "@/components/header/Search";
import SiderMenu from "@/components/sider-menu/";
import { observer } from "mobx-react";
import mobxData from "@/store/mobx-data";
import "@/App.css";

const { Header, Content, Sider } = Layout;

const App: React.FC = () => {
  return (
    <Layout className="app-layout">
      <Header className="app-header">
        <div className="app-logo">
          <img height="36" src={require("@/logo.png")} />
        </div>

        <div className="search">
          <Search />
        </div>
        <Dropdown />
      </Header>
      <Layout className="app-wrapper">
        <Sider width={mobxData.width} className="app-sider">
          <SiderMenu />
        </Sider>
        <Layout className="app-wrapper-in">
          <Content className="app-content">
            <Outlet />
          </Content>
        </Layout>
      </Layout>
    </Layout>
  );
};

export default observer(App);

4、src/pages/login/index.tsx:登录页

import React from "react";
import { useNavigate } from "react-router-dom";
import { Dropdown, Space, Button, Checkbox, Form, Input } from "antd";
import {
  DownloadOutlined,
  GlobalOutlined,
  DownOutlined,
  LockOutlined,
  UserOutlined
} from "@ant-design/icons";
import "./index.css";

const items1 = [
  {
    key: "1",
    label: "下载客户端"
  },
  {
    key: "2",
    label: "下载证书",
    children: [
      {
        key: "2-1",
        label: "下载应用证书"
      },
      {
        key: "2-2",
        label: "证书安装文档"
      }
    ]
  },
  {
    key: "3",
    label: "RESTFUL API"
  },
  {
    key: "4",
    label: "Web组件"
  }
];

const items2 = [
  {
    key: "5",
    label: "简体中文"
  },
  {
    key: "6",
    label: "繁体中文"
  },
  {
    key: "7",
    label: "ENGLISH"
  }
];

const App: React.FC = () => {
  let navigate = useNavigate();

  const onFinish = (values: string) => {
    console.log("Received values of form: ", values);
    localStorage.setItem("token", "2");
    navigate("/");
  };

  return (
    <div className="container">
      <div className="background-container"></div>
      <div className="wrapper">
        <div className="oem">
          <div className="oem-img"></div>
        </div>

        <div className="index">
          <div className="wrap-header-bar">
            <div className="app-index-bar" style={{ width: "504px" }}>
              <div
                className="app-index-bar-item"
                style={{ paddingRight: "16px" }}
              >
                <Dropdown
                  menu={{
                    items: items1
                  }}
                  trigger={["click"]}
                >
                  <a onClick={e => e.preventDefault()}>
                    <DownloadOutlined
                      style={{
                        fontSize: "14px",
                        cursor: "pointer",
                        marginRight: "5px"
                      }}
                    />
                    <Space>
                      下载
                      <DownOutlined />
                    </Space>
                  </a>
                </Dropdown>
              </div>
              <div className="app-index-bar-item">
                <Dropdown
                  menu={{
                    items: items2
                  }}
                  trigger={["click"]}
                >
                  <a onClick={e => e.preventDefault()}>
                    <GlobalOutlined
                      style={{
                        fontSize: "14px",
                        cursor: "pointer",
                        marginRight: "5px"
                      }}
                    />
                    <Space>
                      简体中文
                      <DownOutlined />
                    </Space>
                  </a>
                </Dropdown>
              </div>
            </div>
          </div>
          <div className="wrap-login">
            <div className="index-panel">
              <div className="logo-wrapper">
                <img
                  className="logo-image"
                  src={require("./images/logo.png")}
                />
              </div>
              <div className="title-wrapper">企业内容门户</div>
              <div className="signin-wrapper">
                <Form
                  name="normal_login"
                  className="login-form"
                  initialValues={{
                    remember: true
                  }}
                  onFinish={onFinish}
                >
                  <Form.Item
                    name="username"
                    rules={[
                      {
                        required: true,
                        message: "请输入账号!"
                      }
                    ]}
                  >
                    <Input
                      prefix={<UserOutlined className="site-form-item-icon" />}
                      placeholder="请输入账号"
                      className="login-form-input"
                    />
                  </Form.Item>
                  <Form.Item
                    name="password"
                    className="login-form-item"
                    rules={[
                      {
                        required: true,
                        message: "请输入密码!"
                      }
                    ]}
                  >
                    <Input
                      prefix={<LockOutlined className="site-form-item-icon" />}
                      type="password"
                      placeholder="请输入密码"
                      className="login-form-input"
                    />
                  </Form.Item>
                  <Form.Item>
                    <Form.Item name="remember" valuePropName="checked" noStyle>
                      <Checkbox>记住登录状态</Checkbox>
                    </Form.Item>
                  </Form.Item>

                  <Form.Item>
                    <Button
                      type="primary"
                      htmlType="submit"
                      className="login-form-button"
                    >
                      登 录
                    </Button>
                  </Form.Item>
                </Form>
              </div>
            </div>
          </div>
          <div className="wrap-footer">
            <div>
              <div className="login-view-all">
                登录即表示同意<a>用户协议</a>
                <span>、 </span>
                <span>
                  <a>隐私政策</a>
                </span>
              </div>
            </div>
            <div className="split"></div>
            <div className="app-index-about" style={{ marginTop: "0px" }}>
              <span className="version-information">版本信息</span>
              <div className="app-index-about-row">
                <span className="app-index-separator">&nbsp;I&nbsp;</span>
                <a
                  className="app-index-record"
                  href="http://beian.miit.gov.cn"
                  target="_blank"
                >
                  沪ICP备09089247号-9
                </a>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default App;

 5、src/pages/404/index.tsx:错误页

import React from "react"
import {Button} from "antd"

const App: React.FC = () => {
    return <div>
        <p>404,当前页面不存在!</p>
        <div><Button type="primary" onClick={()=>window.history.back()}>返回</Button></div>
    </div>
}

export default App;

6、components/sider-menu/index.tsx:导航组件,使用<NavLink></NavLink>

import React, { useState } from "react";
import { Button, Tooltip } from "antd";
import {
  HomeOutlined,
  FolderOutlined,
  AppstoreOutlined,
  ReadOutlined,
  TableOutlined,
  ProductOutlined,
  MenuFoldOutlined,
  MenuUnfoldOutlined
} from "@ant-design/icons";
import { NavLink } from "react-router-dom";
import mobxData from "@/store/mobx-data";
import "./index.css";

const App: React.FC = () => {
  const [status, setStatus] = useState(false);

  const onChangeWidth = () => {
    const elements = document.querySelectorAll(".menu-item dd") as NodeListOf<
      HTMLElement
    >;

    if (status) {
      mobxData.setWidth(90);

      for (let i = 0; i < elements.length; i++) {
        (elements[i].style as any).display = "block";
      }
    } else {
      mobxData.setWidth(60);

      for (let i = 0; i < elements.length; i++) {
        (elements[i].style as any).display = "none";
      }
    }

    setStatus(!status);
  };

  return (
    <div className="menu">
      <div className="menu-item-all">
        <NavLink to="/">
          <dl className="menu-item">
            <dt>
              {status ? (
                <Tooltip
                  placement="right"
                  title="我的门户"
                  className="menu-tooltip"
                >
                  <Button type="text" icon={<HomeOutlined />} />
                </Tooltip>
              ) : (
                <HomeOutlined />
              )}
            </dt>
            <dd>我的门户</dd>
          </dl>
        </NavLink>
        <NavLink to="/timeline">
          <dl className="menu-item">
            <dt>
              {status ? (
                <Tooltip
                  placement="right"
                  title="文档中心"
                  className="menu-tooltip"
                >
                  <Button type="text" icon={<FolderOutlined />} />
                </Tooltip>
              ) : (
                <FolderOutlined />
              )}
            </dt>
            <dd>文档中心</dd>
          </dl>
        </NavLink>
        <NavLink to="/collapse">
          <dl className="menu-item">
            <dt>
              {status ? (
                <Tooltip
                  placement="right"
                  title="工作中心"
                  className="menu-tooltip"
                >
                  <Button type="text" icon={<AppstoreOutlined />} />
                </Tooltip>
              ) : (
                <AppstoreOutlined />
              )}
            </dt>
            <dd>工作中心</dd>
          </dl>
        </NavLink>
        <dl className="menu-item">
          <dt>
            {status ? (
              <Tooltip
                placement="right"
                title="知识中心"
                className="menu-tooltip"
              >
                <Button type="text" icon={<ReadOutlined />} />
              </Tooltip>
            ) : (
              <ReadOutlined />
            )}
          </dt>
          <dd>知识中心</dd>
        </dl>
        <dl className="menu-item">
          <dt>
            {status ? (
              <Tooltip
                placement="right"
                title="表格中心"
                className="menu-tooltip"
              >
                <Button type="text" icon={<TableOutlined />} />
              </Tooltip>
            ) : (
              <TableOutlined />
            )}
          </dt>
          <dd>表格中心</dd>
        </dl>
        <NavLink to="/app">
          <dl className="menu-item">
            <dt>
              {status ? (
                <Tooltip
                  placement="right"
                  title="应用"
                  className="menu-tooltip"
                >
                  <Button type="text" icon={<ProductOutlined />} />
                </Tooltip>
              ) : (
                <ProductOutlined />
              )}
            </dt>
            <dd>应用</dd>
          </dl>
        </NavLink>
      </div>

      <div className="collapse">
        <Tooltip placement="right" title={status ? "展开" : "收起"}>
          <Button
            type="text"
            icon={
              status ? (
                <MenuUnfoldOutlined onClick={onChangeWidth} />
              ) : (
                <MenuFoldOutlined onClick={onChangeWidth} />
              )
            }
            onClick={onChangeWidth}
          />
        </Tooltip>
      </div>
    </div>
  );
};

export default App;

7、/src/routes/index.tsx:路由文件,主要是三个页面:首页(及子页面)、登录页、错误页

使用<Suspense></Suspense>是为了防止在使用路由懒加载时报错及防止页面切换时页面抖动。

import React, { Suspense, lazy } from "react";
import Auth from "@/components/auth";
import Layout from "@/Layout"
import Home from "@/pages/home/";
 
const Collapse = lazy(() => import("@/pages/collapse/"));
const Timeline = lazy(() => import("@/pages/timeline/"));
const Application = lazy(() => import("@/pages/application/"));
const Login = lazy(() => import("@/pages/login/"));
const NotFound = lazy(()=>import("@/pages/404/"))
 
const withLoadingComponent = (comp: JSX.Element) => (
  <Suspense fallback={<div>Loading...</div>}>{comp}</Suspense>
)
 
const routes = [
  {
    path: "/",
    element: <Layout />,
    children: [
      {
        index: true,
        element: withLoadingComponent(<Home />),
      },
      {
        path: "collapse",
        element: withLoadingComponent(<Auth><Collapse /></Auth>),
      },
      {
        path: "timeline",
        element: withLoadingComponent(<Auth><Timeline /></Auth>),
      },
      {
        path: "app",
        element: withLoadingComponent(<Auth><Application /></Auth>),
      }
    ]
  },
  {
    path: "/login",
    element: withLoadingComponent(<Auth><Login /></Auth>),
  },
  { path: '*', element: <NotFound /> },  
];
 
export default routes;

8、路由鉴权:src/components/auth/index.tsx

  • 直接输入登录页,如果没有登录则进入登录页;如果已经登录,则跳转至首页;
  • 输入子页,如果没有登录,则跳转至登录页;如果已经登录,则直接进入该页;
import React from "react";
// import { useNavigate } from "react-router-dom";
import { useLocation, Navigate } from "react-router-dom";

interface Props {
  children: React.ReactElement;
}

export default function Auth({ children }: Props) {
  const {pathname} = useLocation();
  const isAuth = localStorage.getItem("token");

  if (pathname === "/login") {
    if (isAuth && Number(isAuth) !== 1) {
      return <Navigate to="/" />;
    } else {
      return <>{children}</>; // 写成:return <Navigate to="/login" />会造成无限循环
    }
  }

  if (isAuth && Number(isAuth) !== 1) {
    return <>{children}</>;
  } else {
    return <Navigate to="/login" />;
  }
}

四、三种方法比较:

使用useRoutes()创建的方式比前两者多了一个页面:

import React, { Suspense } from "react";
import { useRoutes } from "react-router-dom"
import routes from "@/routes/"
import "@/App.css";

const App: React.FC = () => {
  const myRoutes = useRoutes(routes);

  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        {myRoutes}
      </Suspense>
    </div>
  );
};

export default App;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值