使用 React Router v6 在 React 中实现面包屑

面包屑在网页开发中非常重要,因为它们为用户提供了一种跟踪其在网页中当前位置的方法,并有助于网页导航。

在本文中,我们将使用 react-router v6 和 bootstrap 在 react 中实现面包屑。

react-router v6 是 react 和 react native 中使用的路由库,用于在网页或 web 应用程序中导航。

我们的实现使用 typescript,但它也可以轻松用于基于 javascript 的项目。

设置

首先,如果尚未安装的话,让我们在我们的项目中安装react-router-dom:

npm 安装react-router-dom

或者替代方案,使用纱线:

纱线添加react-router-dom

让我们也安装 bootstrap 来设计我们的组件:

npm 安装引导

实现我们的组件

然后我们创建一个 breadcrumbs.tsx 组件,它将包含面包屑的标记,还包括确定相对于根位置的当前位置的必要逻辑。

让我们首先为组件添加一个简单的标记:

<div classname="text-primary">
   <nav aria-label="breadcrumb"><ol classname="breadcrumb">
<li classname="breadcrumb-item pointer">
          <span classname="bi bi-arrow-left-short me-1"></span>
            back
        </li>
      </ol></nav>
</div>

该组件目前只有一个后退按钮。让我们为后退按钮添加一个简单的实现,这样当单击时,应该加载上一页:

const goback = () =&gt; {
    window.history.back();
  };

下一步将编写一个函数,该函数将使用 matchroutes 函数来获取当前路由并应用转换来过滤出与当前路由相关的所有路由。

matchroute 接受 agnosticrouteobject 类型的对象数组并返回 agnosticroutematch[] | null 其中 t 是我们传入的对象的类型。

另外需要注意的是,该对象必须包含名为 path 的属性。

让我们首先为我们的路线声明一个接口:

interface iroute {
  name: string;
  path: string; //important
}

然后让我们声明我们的路线:

const routes: iroute[] = [
  {
    path: '/home',
    name: 'home'
  },
  {
    path: '/home/about',
    name: 'about'
  },
  {
    path: '/users',
    name: 'users'
  },
  {
    path: '/users/:id',
    name: 'user'
  },
  {
    path: '/users/:id/settings/edit',
    name: 'edit user settings'
  }
];

我们还声明了一个变量来保存 uselocation 钩子,还声明了另一个变量来保存面包屑的状态:

const location = uselocation();
const [crumbs, setcrumbs] = usestate<iroute>([]);
</iroute>

接下来,让我们实现我们的功能:

const getpaths = () =&gt; {
  const allroutes = matchroutes(routes, location);
  const matchedroute = allroutes ? allroutes[0] : null;
  let breadcrumbs: iroute[] = [];
  if (matchedroute) {
    breadcrumbs = routes
      .filter((x) =&gt; matchedroute.route.path.includes(x.path))
      .map(({ path, ...rest }) =&gt; ({
        path: object.keys(matchedroute.params).length
          ? object.keys(matchedroute.params).reduce(
              (path, param) =&gt; path.replace(`:${param}`, matchedroute.params[param] as string), path)
          : path,
        ...rest,
      }));
  }
  setcrumbs(breadcrumbs);
};

在这里,我们首先获取与当前位置匹配的所有路线:

const allroutes = matchroutes(路线, 位置);

然后我们快速检查是否返回任何结果,并选择第一个:

常量匹配路由=所有路由? allroutes[0] : null;

接下来,我们过滤掉所有与当前路由匹配的路由:

routes.filter((x) =>matchedroute.route.path.includes(x.path))

然后让我们使用结果创建一个新数组,检查路径是否有参数,然后用参数值交换动态路由:

.map(({ path, ...rest }) =&gt; ({
          path: object.keys(matchedroute.params).length
            ? object.keys(matchedroute.params).reduce(
                (path, param) =&gt; path.replace(`:${param}`, matchedroute.params[param] as string),
                path
              )
            : path,
          ...rest,
        }));

这确保了如果我们在路由中将路由声明为 /users/:id/edit 并将 id 传递为 1,那么我们将得到 /users/1/edit。

接下来,让我们在 useeffect 中调用我们的函数,以便每次我们的位置发生变化时它都会运行:

useeffect(() =&gt; {
    getpaths();
  }, [location]);

完成此操作后,我们就可以在标记中使用面包屑:

{crumbs.map((x: iroute, key: number) =&gt;
  crumbs.length === key + 1 ? ({x.name}
) : (
{x.name}
) )} 

在这里,显示所有的面包屑及其链接,除了最后一个仅显示名称的面包屑。

这样,我们现在就有了完整的 breadcrumbs.tsx 组件:

import { useEffect, useState } from 'react';
import { Link, matchRoutes, useLocation } from 'react-router-dom';

interface IRoute {
  name: string;
  path: string;
}

const routes: IRoute[] = [
  {
    path: '/home',
    name: 'Home',
  },
  {
    path: '/home/about',
    name: 'About',
  },
  {
    path: '/users',
    name: 'Users',
  },
  {
    path: '/users/:id/edit',
    name: 'Edit Users by Id',
  },
];

const Breadcrumbs = () =&gt; {
  const location = useLocation();
  const [crumbs, setCrumbs] = useState<iroute>([]);

  const getPaths = () =&gt; {
    const allRoutes = matchRoutes(routes, location);
    const matchedRoute = allRoutes ? allRoutes[0] : null;
    let breadcrumbs: IRoute[] = [];
    if (matchedRoute) {
      breadcrumbs = routes
        .filter((x) =&gt; matchedRoute.route.path.includes(x.path))
        .map(({ path, ...rest }) =&gt; ({
          path: Object.keys(matchedRoute.params).length
            ? Object.keys(matchedRoute.params).reduce(
                (path, param) =&gt; path.replace(`:${param}`, matchedRoute.params[param] as string),
                path
              )
            : path,
          ...rest,
        }));
    }
    setCrumbs(breadcrumbs);
  };

  useEffect(() =&gt; {
    getPaths();
  }, [location]);

  const goBack = () =&gt; {
    window.history.back();
  };

  return (
    <div classname="">
      <nav aria-label="breadcrumb"><ol classname="breadcrumb">
<li classname="breadcrumb-item pointer" onclick="{goBack}">
            <span classname="bi bi-arrow-left-short me-1"></span>
            Back
          </li>
          {crumbs.map((x: IRoute, key: number) =&gt;
            crumbs.length === key + 1 ? (
              <li classname="breadcrumb-item">{x.name}</li>
            ) : (
              <li classname="breadcrumb-item">
                <link to="{x.path}" classname=" text-decoration-none">
                  {x.name}
                
              </li>
            )
          )}
        </ol></nav>
</div>
  );
};
export default Breadcrumbs;
</iroute>

然后我们可以在应用程序的任何部分使用该组件,最好是在布局中。

结论

我们已经了解了如何实现一个简单的面包屑组件,我们可以将其添加到我们的应用程序中以改进导航和用户体验。

有用的链接

https://stackoverflow.com/questions/66265608/react-router-v6-get-path-pattern-for-current-route

https://medium.com/@mattywilliams/generating-an-automatic-breadcrumb-in-react-router-fed01af1fc3,这篇文章的灵感来自于此。

相关推荐
Jayson柴17 分钟前
高德地图key
前端·javascript
vener_17 分钟前
ruoyi-python 若依python版本部署及新增模块
前端·javascript·vue.js·ruoyi
谢尔登41 分钟前
【Webpack】优化前端开发环境的热更新效率
前端·webpack·node.js
howard20051 小时前
初试Bootstrap前端框架
前端·bootstrap
Mr.LiLong1 小时前
css 边框流光效果
前端·css
0wioiw01 小时前
Vue+Flask
前端·vue.js·flask
詹姆斯bind1 小时前
简单vue指令实现 el-table 可拖拽表格功能
前端·javascript·vue.js·elementui
凹凸曼打不赢小怪兽1 小时前
elementPlus的tree组件点击后有白色背景
前端·vue.js·elementui
low神2 小时前
React Native使用高德地图
javascript·react native·react.js
行深2 小时前
重构pdfjs阅读器viewer.html,实现双PDF对比(不依赖iframe、embed)
前端