您现在的位置是:首页 >技术教程 >20230602----重返学习-React路由网站首页技术教程

20230602----重返学习-React路由

方朝端 2024-07-23 00:01:02
简介20230602----重返学习-React路由

day-083-eighty-three-20230602-React路由

React路由

  • 新版的是react-router-dom是6版本,而旧版的是5版本。

  • 基于前端路由实现SPA单页面应用,其核心在于:构建路由表(构建路由匹配机制)。

    1. 每一次路由切换(包含刚开始第一次渲染页面),都会拿当前的地址(或者哈希值)去路由表中进行查找匹配,找到相匹配的组件。
      • 包含刚开始第一次渲染页面
    2. 找到的组件放在指定的容器中渲染。

划分路由

  • 常见的路由划分方式:

    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LqE0rl0A-1685721346336)(./如何划分路由.jpg)]

    • 基础页面-基本由路由控制。

      • /user 登录注册所在页。
        • /user/login 登录页。
        • /user/register 注册页。
      • / 主页-首页所在的页面,除登录注册页与404页面。
        • /home 首页。
          • home/watch 监控。
          • /home/woker 控制台。
          • /home/message 消息。
        • /categroy 分类管理。
        • /personal 个人中心。
      • * 404页面。
    • 基础页面-由路由与选项卡控制。

      • / 默认页,重定向到/home
      • /login 登录注册所在页。
        1. 登录页与登录页是使用tag组件进行切换的。
      • /home 主页-首页所在的页面。
        • /home/welcome 首页-欢迎页。
        • home/categroy 分类管理。
        • /home/personal 个人中心。
      • * 404页面。
    • 扁平化路由页面-全部一级路由。

      • / 默认页,重定向到/home
      • /login 登录注册所在页。
      • /home 首页。
      • /categroy 分类管理。
      • /personal 个人中心。
      • * 404页面。
        1. 在二级及以上的路由都可以跳转到404页。
        2. 用户输入错误地址,可以到404页。
  • 一般一个应用,路由只有三层。最多只要5级路由。

  • 一级路由中根路径/要挪到末尾不加exact属性,而二级路由根路径则是根路径放前面加exact属性。

react-router-dom版本V5

  • react-router-dom的V5版本:
    1. 和vue-router不同,没有单独的路由表,需要把路由匹配机制,写在指定组件的特定位置。

      • 特定位置:那一块需要根据不同地址渲染不同组件,就把匹配机制写在那。

        import { HashRouter, BrowserRouter, Route, Switch, Redirect } from 'react-router-dom'
        
    2. 视图入口主文件定义一级路由。

      // 1. 导入路由组件HashRouter,BrowserRouter,StaticRouter。
      import {
        HashRouter,
        BrowserRouter,
        StaticRouter,
        Route,
        Switch,
        Redirect,
      } from "react-router-dom";
      
      
      // 1.5. 导入一级路由需要的组件。
      import BasicLayout from "./layout/BasicLayout";
      import UserLayout from "./layout/UserLayout";
      import Error from "./layout/Error";
      
      // 2. 用路由组件把业务组件包起来。
      <HashRouter>
        {/* 4. 只匹配一个组件,如果符合条件,就停止匹配。 */}
        <Switch>
          {/* 3. 定义路由匹配机制。每一条匹配条件,就写一个Route组件。 */}
          {/* <Route exact path="/" component={BasicLayout}></Route> */}
          <Route path="/user" component={UserLayout}></Route>
          {/* <Route path="*" component={Error}></Route> */}
          {/* <Route component={Error}></Route> */}
      
          <Route path="/404" component={Error}></Route>
      
          <Route path="/" component={BasicLayout}></Route>
      
          {/* 5. 定义重定向。 */}
          {/* <Redirect from="*" to="/404"></Redirect> */}
          <Redirect to="/404"></Redirect>
          {/* 6. 把`/`移动到后方,这个404已经不会重定向了,但习惯于把它放到后方用于提示。 */}
      
        </Switch>
      </HashRouter>
      
      1. 导入路由组件HashRouter,BrowserRouter,StaticRouter中其中一个。以及路由匹配组件Route,以及一个路由重定向组件Redirect,以及仅匹配单个路由组件Switch。
      2. 用路由组件把业务组件包起来。
      3. 定义路由匹配机制。每一条匹配条件,就写一个Route组件。
        • Route组件的默认是宽松匹配,只要路由地址包含了Route组件的path属性,就默认匹配上了。
        • Route组件的exact属性可以让路由被精准地匹配,只有路由地址与Route组件的path属性一模一样才算匹配成功。
      4. 使用Switch组件把Route组件组包裹起来,让Route组件组中只匹配一个组件,如果符合条件,就停止匹配。
      5. 使用Redirect组件定义重定向。
      • fang/f20230602/route基础/src/App.jsx

        import React from "react";
        // 1. 导入路由组件HashRouter,BrowserRouter,StaticRouter。
        import {
          HashRouter,
          BrowserRouter,
          StaticRouter,
          Route,
          Switch,
          Redirect,
        } from "react-router-dom";
        /* //{HashRouter,BrowserRouter,StaticRouter,: 控制使用何种路由切换方式,是Hash路由还是History路由。
          - Switch组件:控制如果某一个Route匹配成功,则不再继续向下匹配了!
          - Redirect:重定向,语法和Route类似,只不过其不需要component,而是基于to来指定重定向后的地址,并且基于from!
          - Route:构建路由的匹配机制。
            - path 匹配地址。
              - 当路由切换完毕或页面刷新,会拿最新的路由地址,和ROute中的path进行匹配;找到匹配项后,把对应的component组件,在此位置进行渲染!
            - component 需要渲染的组件。
        */
        
        // 4. 导入一级路由需要的组件。
        import BasicLayout from "./layout/BasicLayout";
        import UserLayout from "./layout/UserLayout";
        import Error from "./layout/Error";
        
        const App = function App() {
          return (
            // 2. 用路由组件把业务组件包起来。
            <HashRouter>
              {/* 4. 只匹配一个组件,如果符合条件,就停止匹配。 */}
              <Switch>
                {/* 3. 定义路由匹配机制。每一条匹配条件,就写一个Route组件。 */}
                {/* <Route exact path="/" component={BasicLayout}></Route> */}
                <Route path="/user" component={UserLayout}></Route>
                {/* <Route path="*" component={Error}></Route> */}
                {/* <Route component={Error}></Route> */}
        
                <Route path="/404" component={Error}></Route>
        
                <Route path="/" component={BasicLayout}></Route>
        
                {/* 5. 定义重定向。 */}
                {/* <Redirect from="*" to="/404"></Redirect> */}
                <Redirect to="/404"></Redirect>
                {/* 6. 把`/`移动到后方,这个404已经不会重定向了,但习惯于把它放到后方用于提示。 */}
        
              </Switch>
            </HashRouter>
          );
        };
        export default App;
        
      • HashRouter组件/BrowserRouter组件:控制使用何种路由切换方式,是 Hash路由 还是 History路由

      • Switch组件:控制如果某一个Route匹配成功,则不再继续向下匹配了。

      • Redirect组件:重定向,语法和Route类似,只不过其不需要component,而是基于 to 来指定重定向后的地址,并且基于from来代替path

      • Route组件:构建路由的匹配机制。

        • path:匹配地址。
          • 当路由切换完毕或页面刷新,会拿最新的路由地址,和Route中的path进行匹配;找到匹配项后,把对应的component组件在此位置进行渲染!

            路由地址path值是否匹配是否精准匹配
            //
            //user
            /user/
            /user/user
            /user2/user
            /user/login/user
          • 默认是按照整体进行匹配的(一个完整的/xxx算是一个整体),如果路由地址中有一到多个整体,其中有一部分整体path值一致,则说明匹配,反之是不匹配!/也算一个整体,所以默认情况下/xxx都会匹配/

        • exact:开启精准匹配,要求路由地址必须和path一模一样才算匹配成功。
          • 一般放在path="/",或者其它组件上。
        • component:需要渲染的组件。
    3. 在一级路由对应的组件中配置对应的二级路由信息。

      1. 引入Switch, Route, Redirect。
      2. 引入需要用的二级路由组件。
      3. 使用Switch, Route, Redirect配置某个一级路由下的二级路由信息。
      // 1. 引入Switch, Route, Redirect。
      import { Switch, Route, Redirect } from "react-router-dom";
      // 2. 引入需要用的二级路由组件
      import Login from "@/views/Login";
      import Register from "@/views/Register";
      
      {/* 3. 使用Switch, Route, Redirect配置某个一级路由下的二级路由信息。 */}
      <Switch>
        <Redirect exact from="/user" to="/user/login" />
        <Route path="/user/login" component={Login} />
        <Route path="/user/register" component={Register} />
        <Redirect to="/404" />
      </Switch>
      
      1. 一级路由对应的组件一般在React阶段/day0602/src「router基础运用」/layout这个目录中。
      2. 一级路由对应组件的根目录一般用重定向组件Redirect的exact属性来指定精准匹配及重定向到该一级路由对应组件的某个二级路由上。
      • 代码:
        • React阶段/day0602/src「router基础运用」/layout/UserLayout.jsx 有二级路由。

          import React from "react";
          import { Tabs } from "antd";
          import styled from "styled-components";
          import backgroundImg from "@/assets/images/background.svg";
          import logo from "@/assets/images/logo.svg";
          // 1. 引入Switch, Route, Redirect。
          import { Switch, Route, Redirect } from "react-router-dom";
          
          // 2. 引入需要用的二级路由组件
          import Login from "@/views/Login";
          import Register from "@/views/Register";
          
          /* 组件样式 */
          const UserLayoutStyle = styled.div`
            position: relative;
            height: 100%;
            background: url(${backgroundImg}) no-repeat;
            background-size: 100%;
          
            .content {
              position: absolute;
              top: 100px;
              left: 50%;
              margin-left: -165px;
              width: 330px;
            }
          
            .header {
              .title {
                display: flex;
                justify-content: center;
                align-items: center;
                line-height: 44px;
                font-size: 33px;
                font-weight: normal;
          
                img {
                  margin-right: 10px;
                  width: 44px;
                  height: 44px;
                }
              }
          
              .subtitle {
                margin: 12px 0 40px 0;
                text-align: center;
                font-size: 14px;
                color: rgba(0, 0, 0, 0.45);
              }
            }
          
            .ant-tabs {
              margin-bottom: 10px;
          
              .ant-tabs-nav {
                &:before {
                  border-bottom-color: #ddd;
                }
              }
          
              .ant-tabs-tab {
                padding: 0 10px;
                font-size: 16px;
                line-height: 40px;
              }
            }
          `;
          
          const UserLayout = function UserLayout() {
            // Tab页卡的数据
            const tabItem = [
              {
                label: `用户登录`,
                key: "login",
              },
              {
                label: `用户注册`,
                key: "register",
              },
            ];
          
            return (
              <UserLayoutStyle>
                <div className="content">
                  <div className="header">
                    <h1 className="title">
                      <img src={logo} alt="" />
                      <span>Ant Design</span>
                    </h1>
                    <p className="subtitle">
                      Ant Design 是西湖区最具影响力的 Web 设计规范
                    </p>
                  </div>
                  <Tabs centered defaultActiveKey="login" items={tabItem} />
                  {/* 登录/注册二级路由的位置 */}
          
                  {/* 3. 使用Switch, Route, Redirect配置某个一级路由下的二级路由信息。 */}
                  <Switch>
                    <Redirect exact from="/user" to="/user/login" />
                    <Route path="/user/login" component={Login} />
                    <Route path="/user/register" component={Register} />
                    <Redirect to="/404" />
                  </Switch>
                </div>
              </UserLayoutStyle>
            );
          };
          export default UserLayout;
          
        • React阶段/day0602/src「router基础运用」/layout/BasicLayout.jsx 有二级路由,需要配置。

          import { useState } from "react";
          import { Menu, Button } from "antd";
          import {
            HomeOutlined,
            ClusterOutlined,
            UserOutlined,
            MenuUnfoldOutlined,
            MenuFoldOutlined,
          } from "@ant-design/icons";
          import styled from "styled-components";
          import logo from "@/assets/images/logo.svg";
          import avatar from "@/assets/images/touxiang.png";
          
          // 1. 引入Switch, Route, Redirect。
          import { Switch, Route, Redirect } from "react-router-dom";
          
          // 2. 引入需要用的二级路由组件
          import Home from "@/views/Home";
          import Category from "@/views/Category";
          import Personal from "@/views/Personal";
          
          /* 组件样式 */
          const BasicLayoutStyle = styled.div`
            height: 100%;
            overflow: hidden;
          
            .header {
              box-sizing: border-box;
              padding: 0 15px;
              height: 48px;
              background: #001529;
              display: flex;
              justify-content: space-between;
              align-items: center;
          
              .logo,
              .info {
                line-height: 48px;
                font-size: 18px;
                color: #fff;
                display: flex;
                align-items: center;
          
                img {
                  margin-right: 10px;
                  width: 35px;
                  height: 35px;
                }
              }
          
              .info {
                font-size: 14px;
          
                img {
                  width: 30px;
                  height: 30px;
                }
              }
            }
          
            .content {
              height: calc(100% - 48px);
              display: flex;
          
              .menu-box {
                height: 100%;
                background: #001529;
          
                .ant-btn {
                  margin-left: 4px;
                  background: transparent;
                  box-shadow: none;
                }
          
                .ant-menu-item {
                  padding: 0 24px;
                }
          
                .ant-menu-inline-collapsed {
                  .ant-menu-item {
                    padding: 0 28px;
                  }
                }
              }
          
              .view-box {
                box-sizing: border-box;
                padding: 15px;
                height: 100%;
                flex-grow: 1;
          
                .component {
                  height: 100%;
                  overflow-y: auto;
                  overflow-x: hidden;
                  background: #fff;
                }
              }
            }
          `;
          
          const BasicLayout = function BasicLayout() {
            // 左侧Menu的数据
            const menuItem = [
              {
                key: "home",
                label: "控制面板",
                icon: <HomeOutlined />,
              },
              {
                key: "category",
                label: "分类管理",
                icon: <ClusterOutlined />,
              },
              {
                key: "personal",
                label: "个人中心",
                icon: <UserOutlined />,
              },
            ];
          
            // 定义状态
            let [collapsed, setCollapsed] = useState(false);
          
            return (
              <BasicLayoutStyle>
                <div className="header">
                  <h2 className="logo">
                    <img src={logo} alt="" />
                    Ant Design
                  </h2>
                  <div className="avatar">
                    <p className="info">
                      <img src={avatar} alt="" />
                      海贼王-路飞
                    </p>
                  </div>
                </div>
                <div className="content">
                  <div className="menu-box">
                    <Button
                      type="primary"
                      onClick={() => {
                        setCollapsed(!collapsed);
                      }}
                    >
                      {collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
                    </Button>
                    <Menu
                      mode="inline"
                      theme="dark"
                      items={menuItem}
                      defaultSelectedKeys={["home"]}
                      inlineCollapsed={collapsed}
                    />
                  </div>
                  <div className="view-box">
                    <div className="component">
                      {/* 主页的二级路由 */}
          
                      {/* 3. 使用Switch, Route, Redirect配置某个一级路由下的二级路由信息。 */}
                      <Switch>
                        <Redirect exact from="/" to="/home" />
                        <Route path="/home" component={Home} />
                        <Route path="/category" component={Category} />
                        <Route path="/personal" component={Personal} />
                        <Redirect to="/404" />
                      </Switch>
                    </div>
                  </div>
                </div>
              </BasicLayoutStyle>
            );
          };
          export default BasicLayout;
          
        • React阶段/day0602/src「router基础运用」/layout/Error.jsx 无二级路由,不需要配置。

          import React from "react";
          import { Button, Empty } from "antd";
          import styled from "styled-components";
          
          /* 组件的样式 */
          const ErrorStyle = styled.div`
            height: 100%;
            overflow: hidden;
          
            .ant-empty {
              position: relative;
              top: 100px;
            }
          `;
          
          const Error = function Error() {
            return (
              <ErrorStyle>
                <Empty description={<span>很遗憾,您访问的页面不存在!</span>}>
                  <Button type="primary">返回首页</Button>
                </Empty>
              </ErrorStyle>
            );
          };
          export default Error;
          
    4. 在二级路由对应的组件中配置对应的三级路由信息。

      1. 引入Switch, Route, Redirect。
      2. 引入需要用的二级路由组件。
      3. 使用Switch, Route, Redirect配置某个二级路由下的三级路由信息。
      // 1. 引入Switch, Route, Redirect。
      import { Switch, Route, Redirect } from "react-router-dom";
      
      // 2. 引入需要用的二级路由组件。
      import Watch from "./home/Watch";
      import Worker from "./home/Worker";
      import Message from "./home/Message";
      
            {/* 3. 使用Switch, Route, Redirect配置某个二级路由下的三级路由信息。 */}
            <Switch>
              <Redirect exact from="/home" to="/home/watch" />
              <Route path="/home/watch" component={Watch} />
              <Route path="/home/worker" component={Worker} />
              <Route path="/home/message" component={Message} />
              <Redirect to="/404" />
            </Switch>
      
      1. 二级路由及二级路由以下对应的组件一般在React阶段/day0602/src「router基础运用」/views这个目录中。
      2. 一级路由对应组件的根目录一般用重定向组件Redirect的exact属性来指定精准匹配及重定向到该一级路由对应组件的某个二级路由上。
      import React from "react";
      import styled from "styled-components";
      
      // 1. 引入Switch, Route, Redirect。
      import { Switch, Route, Redirect } from "react-router-dom";
      
      // 2. 引入需要用的二级路由组件。
      import Watch from "./home/Watch";
      import Worker from "./home/Worker";
      import Message from "./home/Message";
      
      /* 组件样式 */
      const HomeStyle = styled.div`
        padding: 10px;
      
        .nav-box {
          display: flex;
          border-bottom: 1px solid #eee;
      
          a {
            padding: 0 20px;
            line-height: 40px;
            font-size: 15px;
            color: #000;
          }
        }
      `;
      
      const Home = function Home() {
        return (
          <HomeStyle>
            <nav className="nav-box">
              <a href="#/home/watch">数据监控</a>
              <a href="#/home/worker">工作台</a>
              <a href="#/home/message">消息中心</a>
            </nav>
            {/* 首页的三级路由 */}
            {/* 3. 使用Switch, Route, Redirect配置某个二级路由下的三级路由信息。 */}
            <Switch>
              <Redirect exact from="/home" to="/home/watch" />
              <Route path="/home/watch" component={Watch} />
              <Route path="/home/worker" component={Worker} />
              <Route path="/home/message" component={Message} />
              <Redirect to="/404" />
            </Switch>
          </HomeStyle>
        );
      };
      export default Home;
      

react-router创建流程

  1. 规划好路由方案。
  2. 规划文件结构。
    • 文件结构示例:
      • fang/f20230602/src/api 处理接口相关的。
      • fang/f20230602/src/assets 放置静态资源的。
        • fang/f20230602/src/assets/images 静态资源-图片放置的地方。
        • fang/f20230602/src/assets/reset.min.css 样式重置文件。
      • fang/f20230602/src/views 放各业务组件,一般是二级路由组件及以下的路由组件。
        • fang/f20230602/src/views/Login.jsx 登录页。
      • fang/f20230602/src/layout 放置布局模块,一般是一级路由页面。
        1. 404报错页也可以不放在这,因为太简单了。
          • 不过个人建议放在这里,那么这个布局里就全都放置了一级路由,组件逻辑更统一。
        • fang/f20230602/src/layout/UserLayout.jsx 登录注册布局。
        • fang/f20230602/src/layout/BasicLayout.jsx 首页所在页。
        • fang/f20230602/src/layout/Error.jsx 404错误页。
      • fang/f20230602/src/index.jsx 程序入口主文件,主要用来处理程序功能。
      • fang/f20230602/src/index.less 全局样式的less文件。
      • fang/f20230602/src/App.jsx 视图入口主文件,项目根组件。处理视图及路由。一般用来匹配一级路由。
  3. 在视图入口主文件中匹配一级路由。

react-router-dom文件

  • 是通过插件react-router-dom来导入的。

    import {
      HashRouter,
      BrowserRouter,
      StaticRouter,
      Route,
      Switch,
      Redirect,
    } from "react-router-dom";
    
  • react-router-dom常见组件:

    • 路由组件:
      • HashRouter:哈希路由组件,控制内部的组件模式是Hash路由。
      • BrowserRouter:浏览器路由组件,控制内部的组件模式是History浏览器路由。
        • 也叫历史路由。
      • StaticRouter:静态路由组件,这个是后端渲染时用的。
    • Route:构建路由的匹配机制。
      • path 匹配地址。
        • 当路由切换完毕或页面刷新,会拿最新的路由地址,和ROute中的path进行匹配;找到匹配项后,把对应的component组件,在此位置进行渲染!
      • component 需要渲染的组件。
    • Switch:控制如果某一个Route匹配成功,则不再继续向下匹配了!
    • Redirect:重定向,语法和Route类似,只不过其不需要component,而是基于to来指定重定向后的地址,并且基于from!

路由统一管理

  1. 创建一个文件夹,用于存放路由相关的信息。

    • fang/f20230602/src/router 用于存放路由相关的信息,以后路由相关的处理,统一放在这里。
      • fang/f20230602/src/router/routes.js 用于存放总体的路由信息表。

        1. 路由表中的每一项都是对象,参照着vue-router的规则来。
          • 每一项的属性:
            • path:‘’ 需要匹配的地址,也是redirect模式下的from。

            • name:undefined 路由名字。

            • component:null 路由匹配后需要渲染的组件。

            • render:undefined 某些情况下,传递的不是component而是render。

            • exact:undefined 是否开启精准匹配。

            • redirect:undefined 设置redirect后,则开启重定向模式,redirect存储的是重定向后的地址。

            • meta:{} 路由元信息,即我们自己给每一个路由设置的自定义信息。

            • children:undefined 子路由信息,如果有子路由,则值是一个数组。

        /* //
        - 路由表中的每一项都是对象,参照着vue-router的规则来。
          - 每一项的属性:
            - path:'' 需要匹配的地址,也是redirect模式下的from。
            - name:undefined 路由名字。
            - component:null 路由匹配后需要渲染的组件。
            - render:undefined 某些情况下,传递的不是component而是render。
            - exact:undefined 是否开启精准匹配。
        
            - redirect:undefined 设置redirect后,则开启重定向模式,redirect存储的是重定向后的地址。
            - meta:{} 路由元信息,即我们自己给每一个路由设置的自定义信息。
            - children:undefined 子路由信息,如果有子路由,则值是一个数组。
        */
        
        import UserLayout from "@/layout/UserLayout";
        import Login from "@/views/Login";
        import Register from "@/views/Register";
        import Error from "@/layout/Error";
        
        import BasicLayout from "@/layout/BasicLayout";
        import Home from "@/views/Home";
        import Category from "@/views/Category";
        import Personal from "@/views/Personal";
        
        import Watch from "@/views/home/Watch";
        import Worker from "@/views/home/Worker";
        import Message from "@/views/home/Message";
        
        // User下的二级路由:
        const userChildren = [
          {
            path: "/user",
            exact: true,
            redirect: "/user/login",
          },
          {
            path: "/user/login",
            name: "login",
            meta: { title: "用户登录" },
            component: Login,
          },
          {
            path: "/user/register",
            name: "register",
            meta: { title: "用户注册" },
            component: Register,
          },
        ];
        
        // Home(控制面板)下的三级路由
        const homeChildren = [
          {
            path: "/home",
            exact: true,
            redirect: "/home/watch",
          },
          {
            path: "/home/watch",
            name: "watch",
            meta: { title: "数据监控" },
            component: Watch,
          },
          {
            path: "/home/worker",
            name: "worker",
            meta: { title: "工作台" },
            component: Worker,
          },
          {
            path: "/home/message",
            name: "message",
            meta: { title: "消息中心" },
            component: Message,
          },
        ];
        
        // Basic-主页下的二级路由。
        const basicChildren = [
          {
            path: "/",
            exact: true,
            redirect: "/home",
          },
          {
            path: "/home",
            name: "home",
            meta: { title: "控制面板" },
            component: Home,
            children: homeChildren,
          },
          {
            path: "/category",
            name: "category",
            meta: { title: "分类管理" },
            component: Category,
          },
          {
            path: "/personal",
            name: "personal",
            meta: { title: "个人中心" },
            component: Personal,
          },
        ];
        
        // 一级路由:
        const routes = [
          {
            path: "/user",
            name: "user",
            meta: {},
            component: UserLayout,
            children: userChildren,
          },
          {
            path: "/404",
            name: "error",
            meta: { title: "404错误页" },
            component: Error,
          },
          {
            path: "/",
            name: "basic",
            meta: {},
            component: BasicLayout,
            children: basicChildren,
          },
        ];
        export default routes;
        
      • fang/f20230602/src/router/index.jsx 创建一个路由统一管理组件,用于浅遍历出一个路由数组表示的路由信息。类似vue-route。

        import { Switch, Redirect, Route } from "react-router-dom";
        import routes from "./routes";
        
        const routesArray = routes;
        // 根据传递的name,获取需要迭代的路由表。
        const queryRoutesByName = (name, routes = routesArray) => {
          if (!name) {
            return routes;
          }
          let arr = [];
          const next = (routes) => {
            routes.forEach((item) => {
              //此项是匹配的。
              if (item.name === name) {
                arr = item.children || [];
                return;
              }
              //如果此项不配,并且具备children,则递归深入查找。
              if (item.children) {
                next(item.children);
              }
            });
          };
          next(routes);
          return arr;
        };
        
        // 通用的路由匹配机制。
        //
        // 如果传入一个name,就根据name来对路由表进行深度查找并返回同name属性下的children。如果没传入name或空字符串,则对一级路由进行校验。
        
        const RouterView = function RouterView({ name, routes = routesArray }) {
          console.log(`mememe`);
          let arr = queryRoutesByName(name, routes);
          if (!arr || arr.length === 0) {
            return null;
          }
          // console.log(`路由表`);
          return (
            <Switch>
              {arr.map((item, index) => {
                let { path, component, render, exact, redirect } = item;
        
                // 重定向的规则:
                if (redirect) {
                  let props = {};
                  if (exact) {
                    props.exact = true;
                  }
                  if (path) {
                    props.path = path;
                  }
                  props.to = redirect;
                  // console.log('props',props);
                  return <Redirect key={index} {...props}></Redirect>;
                }
        
                // 正常匹配的规则;
                let props = {};
                if (exact) {
                  props.exact = true;
                }
                props.path = path;
                typeof render === "function"
                  ? (props.render = render)
                  : (props.component = component);
                return <Route key={index} {...props}></Route>;
              })}
              <Redirect to="/404"></Redirect>
            </Switch>
          );
        };
        RouterView.defaultProps = {
          name: "",
        };
        export default RouterView;
        
  2. 在业务组件中需要用到路由表的地方,引入路由统一管理组件,并设置它的name。此时路由统一管理组件会浅遍历出对应name的路由下的各个子节点。

路由跳转

  1. 引入Link组件或NavLink组件。

    import {Link,NavLink} from 'react-router-dom'
    
    • Link与NavLink都是实现路由切换的方式。

      <Link to="要跳转的路由地址">渲染的内容</Link>
      
      • 属性

        • to属性值是字符串与对象
          • to=“/home/watch”
          • to={{pathname:‘/home/watch’,}}
        • replace 如果设置这个属性,则本次路由跳转是替换现有的历史记录,而不是新增记录。
      • 渲染完成的结果还是a标签。

        • 但是它会根据当前路由的模式,自动设置a标签的href属性值。
          • 假设为:<Link to="/home/watch">数据监控</Link>
          • 哈希路由 href='#/home/watch'
          • History路由 href='/home/watch' 在内部点击a标签的时候,阻止了a标签的默认行为,转而基于HistoryAPI实现路由的跳转。
      • NavLink其语法和Link基本上一致,主要区别是:

        • 会拿当前路由的地址和to要跳转的地址进行匹配,默认是非精准匹配,不过我们可以设置exact让其变为精准匹配。
        • 和那一项匹配了,就给当前项设置一个叫做active的样式类。
          • 可以基于activeClassName 修改匹配的样式类名。
          • 也可以直接基于className或style或activeStyle设置选中的样式。
        • 这样我们就可以给当前选中的项,设置选中样式了!
  2. 在业务组件中使用Link组件或NavLink组件。

进阶参考

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。