• 定义面包屑list,每次push当前页面,push前校验是否为第一层级,第一层级清除list
  • 单页面路由需监听页面刷新,缓存list
import React, { useContext, useEffect, useState } from 'react';
import classNames from 'classnames';
import { withRouter } from 'react-router-dom';
import { useLastLocation } from 'react-router-last-location';
import { findIndex } from 'lodash';
import { Breadcrumb } from '@huohua/luca';

import NativePageJump from '@utils/nativePageJump';
import RouterContext from '@components/Context/RouterContext';

import './style.less';

// 历史记录
let PRE_LIST = [];

// 通过name找到记录
const getBreadcrumbName = ({ routes, location }) => {
  return routes.filter(f => {
    // 存在动态参数
    if (
      f?.action?.indexOf(':') !== -1 &&
      f?.action?.split('/')?.length === location?.pathname?.split('/')?.length &&
      location?.pathname?.startsWith(f?.action?.split(':')?.[0])
    ) {
      return f;
    }
    return f?.action === location?.pathname;
  })?.[0];
};

// 获取面包屑记录
function getBreadcrumb({ routes, location, cache, rootPages }) {
  if (location) {
    const cacheUrl = `${location?.pathname}${location?.search}`;
    const route = getBreadcrumbName({ routes, location });
    // 如果当前是二级目录,需要将一级目录手动导入
    if (rootPages?.find(item => item?.id === route?.id)) {
      const parent = routes?.find(item => item.id === route?.pid);
      parent &&
        cache.push({
          path: parent?.action,
          name: parent?.title,
        });
    }
    cache.push({
      path: cacheUrl,
      name: route?.title,
    });
    return cache;
  }
  return [];
}

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

/**
 * 面包屑
 * @constructor
 *  面包屑list 历史路由 + 当前路由
 *  需鉴定页面刷新,存储历史路由
 *  根目录判断依托于星云菜单配置  二级菜单为页面跳转
 *  todo 一级目录  未对应直接页面,点击不可跳转  pid为0
 *  二级目录 为第一层页面
 */
const Bread = ({ routes, location }) => {
  // 获取最后一个地址 - 上个页面地址
  const lastLocation: any = useLastLocation();

  const router: any = useContext(RouterContext);

  // 二级目录
  const [rootPages, setRootPages] = useState<any[]>([]);

  // 面包屑记录
  const [breadRoutes, setBreadRouts] = useState<BreadRoutes[]>([]);

  useEffect(() => {
    if (!routes?.length) return;
    // 二级目录
    const packageRoute = routes?.filter(item => item?.pid === 0 && item?.display);
    // 根目录 -- 星云返回的二级目录
    let _rootPages = [];
    packageRoute?.map(item => {
      const list = routes?.filter(it => it?.pid === item?.id);
      _rootPages = _rootPages.concat(list);
    });
    setRootPages(_rootPages);
  }, [routes]);

  // 监听事件处理
  const listenReload = () => {
    // 设置刷新字段
    window.sessionStorage.setItem('BREAD_PAGE_LOAD', '1');
    // 存储历史记录(不包含当前页面)
    if (PRE_LIST?.length) {
      window.sessionStorage.setItem('BREAD_PRE_LIST', JSON.stringify(PRE_LIST));
    }
  };

  // 监听页面刷新
  useEffect(() => {
    const isReload = window.sessionStorage.getItem('BREAD_PAGE_LOAD');
    if (!isReload) window.sessionStorage.setItem('BREAD_PAGE_LOAD', '0');
    window.addEventListener('beforeunload', listenReload);
    return () => {
      window.removeEventListener('beforeunload', listenReload);
    };
  }, []);

  // 跳转地址
  useEffect(() => {
    if (!routes?.length || !rootPages?.length || !location) return;
    // 当前页面是否刷新
    const isReload = window.sessionStorage.getItem('BREAD_PAGE_LOAD');
    if (!PRE_LIST?.length && isReload === '1') {
      // 历史页面
      PRE_LIST = JSON.parse(window.sessionStorage.getItem('BREAD_PRE_LIST') || '[]');
      window.sessionStorage.setItem('BREAD_PAGE_LOAD', '0');
    } else {
      // 不刷新 --> PRE_LIST 为上个页面之前的历史,需要通过 lastLocation 合成为历史数据
      PRE_LIST = getBreadcrumb({ routes, location: lastLocation, cache: PRE_LIST, rootPages });
    }
    // 当前页面
    let current = [];

    // 二级导航清空数据, 并导入一级导航
    if (rootPages?.find(item => item?.action === location?.pathname)) {
      PRE_LIST = [];
    }

    // 当前路由
    current = getBreadcrumb({ routes, location, cache: current, rootPages });

    // 面包屑
    const result = [...PRE_LIST, ...current];

    // 查找与当前路径相同的第一个路由  并将其从面包屑中去除
    const index = findIndex(result || [], {
      name: getBreadcrumbName({ routes, location })?.title,
    });
    index !== result.length - 1 && result.splice(index + 1, result.length);

    setBreadRouts(() => result);
  }, [location, routes, lastLocation, rootPages]);

  if (breadRoutes.length === 0) return null;

  const handleJumpPage = url => {
    NativePageJump(
      {
        url,
        router,
      },
      {
        isReplace: true,
      },
    );
  };

  return (
    <Breadcrumb className="bread-crumb" separator=">">
      {breadRoutes.map((c, index) => {
        return (
          <Breadcrumb.Item
            className={classNames('crumb', { 'last-crumb': index === breadRoutes?.length - 1 })}
            key={`breadcrumb-${index}`}
            // 一级目录、当前页皆不可点击跳转
            onClick={() => index !== breadRoutes?.length - 1 && index !== 0 && handleJumpPage(c.path)}>
            {c?.name}
          </Breadcrumb.Item>
        );
      })}
    </Breadcrumb>
  );
};

// 导出
export default withRouter(Bread);
作者:|桃小妖|,原文链接: https://segmentfault.com/a/1190000043599640

文章推荐

一分钟学一个 Linux 命令 - find 和 grep

Vue3.3 的新功能的体验(下):泛型组件(Generic Component...

「学习笔记」可持久化线段树

ArcGIS Desktop发布地形高程服务(DEM/DSM)

深度学习--LSTM网络、使用方法、实战情感分类问题

基于docker和cri-dockerd部署k8sv1.26.3

fork语句遇见for循环语句

python爬虫基础教程

深入理解 Python 虚拟机:整型(int)的实现原理及源码剖析

Python <算法思想集结>之抽丝剥茧聊动态规划

程序分析与优化 - 5 指针分析

定制ASP.NET 6.0的应用配置