乐趣区

关于react.js:Bread-面包屑

  • 定义面包屑 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);
退出移动版