# 实现动态面包屑导航

# 完整代码如下

// routes
export const routes: MenuRoute[] = [
  {
    routeProps: {
      path: '/',
      element: <App />,
    },
    children: [
      {
        routeProps: {
          index: true,
          element: <IndexPage />
        },
        title: '首页',
        hideInMenu: true,
        hasMainLayout: false,
      },
      {
        routeProps: {
          path: 'login',
          element: <Login />
        },
        title: '登录',
        hideInMenu: true,
        hasMainLayout: false,
      },
      {
        routeProps: {
          path: 'product-manage',
          element: <ProductManage />,
        },
        title: '商品管理',
        icon: 'product',
        code: PRODUCT_MANAGE.CODE,
        children: [
          {
            routeProps: {
              path: 'create-product',
              element: <Product />,
            },
            title: '创建商品',
            code: PRODUCT_MANAGE.CREATE_PRODUCT,
            hideInMenu: true
          },
          {
            routeProps: {
              path: 'product-detail',
              element: <Product />,
            },
            title: '商品详情',
            code: PRODUCT_MANAGE.VIEW_PRODUCT_DETAIL,
            hideInMenu: true
          },
        ]
      },
      {
        routeProps: {
          path: 'order-manage',
          element: <OrderManage />,
        },
        title: '订单管理',
        code: ORDER_MANAGE.CODE,
        icon: 'order',
      },
      {
        routeProps: {
          path: '*',
          element: <IndexPage />
        },
        hideInMenu: true,
        hasMainLayout: false,
      },
    ]
  }
]
import { Breadcrumb } from 'antd'
import { useLocation, useNavigate } from 'react-router-dom'
import styles from './breadcrumb.module.scss'
import routes, { MenuRoute } from '@/router'
import classNames from 'classnames'

interface BreadcrumbItem extends MenuRoute {
  isLink?: boolean // 是否可点击跳转
}

export default function BreadcrumbPage() {
  const location = useLocation()
  const navigate = useNavigate()

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const flattenRoutes: (arr: MenuRoute[]) => BreadcrumbItem[] = (arr: MenuRoute[]) =>
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    arr.reduce((prev: any[], item: MenuRoute) => {
      prev.push(item)
      return prev.concat(
        Array.isArray(item.children) ? flattenRoutes(item.children) : []
      )
    }, [])

  // 把路由平铺成一维数组
  const flattenRouteArr = flattenRoutes(routes)

  // 获取路径,截取成数组
  const pathArr = location.pathname.substring(1).split('/')
  //面包屑子级数组
  const breadcrumbItems: BreadcrumbItem[] = []
  // 遍历匹配追加到面包屑子级数组
  pathArr.forEach(element => {
    const menu = flattenRouteArr.find((item: BreadcrumbItem) => item.routeProps.path === element)
    if (menu) {
      menu.isLink = !!menu.routeProps.element
      breadcrumbItems.push(menu)
    }
  })

  // 点击面包屑item
  const handleClickItem = (item: BreadcrumbItem) => {
    if (!item.isLink) {
      return
    }
    navigate({
      pathname: item.fullPath || '/'
    })
  }

  return (<div className={styles.breadcrumbPage}>
    当前位置:
    <Breadcrumb>
      {
        breadcrumbItems.map((item: BreadcrumbItem) => <Breadcrumb.Item className={classNames(item.isLink && styles.isLink)} key={item.title} onClick={() => handleClickItem(item)}>{item?.title || '-'}</Breadcrumb.Item>)
      }
    </Breadcrumb>
  </div>)
}

参考文章:

react 实现动态面包屑导航 (opens new window)

更新时间: 2022年10月18日星期二下午5点47分