天天看點

手牽手學習react之左側導航欄路由封裝(七)

手牽手學習react之左側導航欄路由封裝(七)

前言

背景管理系統是前端永遠繞不開的話題,無論技術怎麼革新,檢驗技術最好的标準就是如何做好産品。如今的前端可謂是百花齊放,百家争鳴,甚至學不過來了!吐血~ 本節主要講述如何使用react、react-router-dom封裝側邊欄。

介紹

下載下傳react-router-dom

yarn add react-router-dom
           

react-router-dom

: 基于

react-router

,加入了在浏覽器運作環境下的一些功能:

  • Link

    元件,會渲染一個

    a

    标簽;
  • BrowserRouter

    元件,使用

    pushState

    popState

    事件建構路由;
  • HashRouter

    元件,使用

    window.location.hash

    hashchange

    事件建構路由。
  • react-router-native

    : 基于

    react-router

    ,類似

    react-router-dom

    ,加入了

    react-native

    運作環境下的一些功能。

開始

手牽手學習react之左側導航欄路由封裝(七)

 描述:圖例就是簡單的背景管理系統模闆,左側的導航欄通過路由控制内容區域的顯示。頁面過于簡單,後面會重新替換,見諒!項目的ui是基于antD。

  • 建立views檔案夾放置頁面
  • 在views下分子產品放置各類頁面(首頁:home)
import React, { Component } from "react";
// layout元件
import LayoutAside from "./components/aside";
import LayoutHeader from "./components/header";
import ContainerMain from "../../components/containerMain/Index";
// css
import "./layout.scss";
// antD
import { Layout } from "antd";
const { Sider, Header, Content } = Layout;

export default class Index extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  render() {
    return (
      <Layout className="layout-wrap">
        <Header className="layout-header">
          <LayoutHeader />
        </Header>

        <Layout>
          <Sider className="layout-side">
            <LayoutAside />
          </Sider>
          <Content className="layout-main">
            <ContainerMain />
          </Content>
        </Layout>
      </Layout>
    );
  }
}
           

描述:首頁是由登入頁面進來的。我們從外部引入三個元件LayoutAside、LayoutHeader、ContainerMain,分别展示側邊欄、頭部、内容區。

  • LayoutAside
import React, { Component } from "react";

//asideMenu
import AsideMenu from "../../../components/asideMenu/index";

export default class Aside extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  render() {
    return <AsideMenu />;
  }
}
           
  •  LayoutHeader
import React, { Component, Fragment } from "react";

//css
import "./aside.scss";

export default class Header extends Component {
  constructor(prpos) {
    super(prpos);
    this.state = {};
  }

  render() {
    return (
      <Fragment>
        <h1 className="logo">
          <span>LOGO</span>
        </h1>
      </Fragment>
    );
  }
}
           
  • ContainerMain 
import React, { Component, Fragment } from "react";
import { Switch } from "react-router-dom";
//元件
import User from "../../views/user/index";
import UserAdd from "../../views/user/Add";
//私有路由元件
//私有元件方法
import PrivateRouter from "../privateRouter/index";

export default class ContainerMain extends Component {
  constructor(prpos) {
    super(prpos);
    this.state = {};
  }

  render() {
    return (
      <Fragment>
        <Switch>
          <PrivateRouter exact path="/home/user/list" component={User}></PrivateRouter>
          <PrivateRouter exact path="/home/user/add" component={UserAdd}></PrivateRouter>
        </Switch>
      </Fragment>
    );
  }
}
           

描述:這個頁面是根據路由來展示不同的頁面,裡面引入私有元件方法比對路由。

  • PrivateRouter 
import React from "react";
import { Route, Redirect } from "react-router-dom";
//擷取token
import { getToken } from "../../utils/session";

const PrivateRouter = ({ component: Component, ...rest }) => {
  return (
    <Route
      {...rest}
      render={
        (routePrpos) =>
          getToken() ? <Component {...routePrpos} /> : <Redirect to="/" /> //判斷token,是否重定向到登入頁
      }
    />
  );
};

export default PrivateRouter;
           

描述:這個私有元件是react-router-dom官方提供的,我們在這個方法中做了路由重定向,防止通過路徑通路。

  • AsideMenu 
import React, { Component, Fragment } from "react";
import { Link } from "react-router-dom";

//antd
import { UserOutlined } from "@ant-design/icons";
import { Menu } from "antd";

//路由
import Router from "../../router/index";

const { SubMenu } = Menu;

export default class AsideMenu extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  // 無子級菜單處理
  renderMenu = ({ title, key }) => {
    return (
      <Menu.Item key={key}>
        <Link to={key}>{title}</Link>
      </Menu.Item>
    );
  };

  // 子級判斷處理(遞歸)
  renderSubMenu = ({ title, key, child }) => {
    return (
      <SubMenu key={key} icon={<UserOutlined />} title={title}>
        {child &&
          child.map((item) => {
            return item.child && item.child.length > 0
              ? this.renderSubMenu(item)
              : this.renderMenu(item);
          })}
      </SubMenu>
    );
  };

  render() {
    return (
      <Fragment>
        <Menu
          mode="inline"
          defaultSelectedKeys={["1"]}
          defaultOpenKeys={["sub1"]}
          style={{ height: "100%", borderRight: 0 }}
          theme="dark"
        >
          {Router &&
            Router.map((firstItem) => {
              return firstItem.child && firstItem.child.length > 0
                ? this.renderSubMenu(firstItem)
                : this.renderMenu(firstItem);
            })}
        </Menu>
      </Fragment>
    );
  }
}
           

描述:LayoutAside元件中引入AsideMenu元件,AsideMenu元件主要是根據路由檔案動态展示導航欄目錄,其中renderMenu 、renderSubMenu這兩個方法是最關鍵的,分别對應無子級菜單處理、子級判斷處理(遞歸),然後再render函數中渲染,根據路由檔案是否存在子路由來判斷顯示對應方法。

  • Router 
const router = [
  {
    title: "控制台",
    icon: "home",
    key: "/home",
  },
  {
    title: "使用者管理",
    icon: "laptop",
    key: "/home/user",
    child: [
      {
        key: "/home/user/list",
        title: "使用者清單",
        icon: "",
      },
      {
        key: "/home/user/add",
        title: "添加使用者",
        icon: "",
      },
    ],
  },
  {
    title: "部門管理",
    icon: "bars",
    key: "/home/navigation",
    child: [
      {
        key: "/home/navigation/dropdown",
        title: "部門清單",
        icon: "",
      },
      {
        key: "/home/navigation/menu",
        title: "添加部門",
        icon: "",
        child: [
          {
            key: "/home/navigation/dropdown",
            title: "部門清單",
            icon: "",
          },
          {
            key: "/home/navigation/menu",
            title: "添加部門",
            icon: "",
          },
        ],
      },
    ],
  },
  {
    title: "職位管理",
    icon: "edit",
    key: "/home/entry",
    child: [
      {
        key: "/home/entry/form/basic-form",
        title: "職位清單",
        icon: "",
      },
      {
        key: "/home/entry/form/step-form",
        title: "添加職位",
        icon: "",
      },
    ],
  },
  {
    title: "請假",
    icon: "info-circle-o",
    key: "/home/about1",
  },
  {
    title: "加班",
    icon: "info-circle-o",
    key: "/home/about",
  },
];

export default router;
           

描述:統一放置路由位址的檔案是以這樣形式,判斷是否有子路由是根據child判斷的,是以這邊修改要同時修改AsideMenu檔案中的child判斷。

App.js

import React, { Component } from "react";
import { Switch, Route, BrowserRouter } from "react-router-dom";
import "./app.scss";
// import Home from "./views/Home.js";
import Login from "./views/login/Index";
import Home from "./views/home/Index";
//私有元件
import PrivateRouter from "./components/privateRouter/index";

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  render() {
    return (
      <div className="title">
        <BrowserRouter>
          <Switch>
            <Route exact render={() => <Login />} path="/" />
            <PrivateRouter component={Home} path="/home" />
            {/* <Route exact render={() => <Home />} path="/home" /> */}
          </Switch>
        </BrowserRouter>
      </div>
    );
  }
}
           

描述:這是頁面路由的入口檔案,放置登入路由、以及首頁路由。

結束

  • 目錄結構
手牽手學習react之左側導航欄路由封裝(七)

gitHub位址,歡迎滴滴