Breadcrumb.tsx 3.79 KB
Newer Older
陈帅's avatar
陈帅 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
import React from 'react';
import pathToRegexp from 'path-to-regexp';
import Link from 'umi/link';
import { formatMessage } from 'umi-plugin-react/locale';
import { urlToList } from '../_utils/pathTools';
import { PageHeaderWrapperProps } from '.';
import { MenuDataItem } from '../SiderMenu';
import { BreadcrumbProps as AntdBreadcrumbProps } from 'antd/lib/breadcrumb';

type BreadcrumbProps = PageHeaderWrapperProps;

// 渲染Breadcrumb 子节点
// Render the Breadcrumb child node
const itemRender: AntdBreadcrumbProps['itemRender'] = (route, params, routes, paths) => {
  const last = routes.indexOf(route) === routes.length - 1;
  return last || !route.component ? (
    <span>{route.breadcrumbName}</span>
  ) : (
    <Link to={paths.join('/')}>{route.breadcrumbName}</Link>
  );
};

const renderItemLocal = (item: MenuDataItem): string => {
  if (item.locale) {
    return formatMessage({
      id: item.locale,
      defaultMessage: item.name,
    });
  }
  return item.name as string;
};

export const getBreadcrumb = (
  breadcrumbNameMap: PageHeaderWrapperProps['breadcrumbNameMap'],
  url: string,
): MenuDataItem => {
  if (!breadcrumbNameMap) {
    return {
      path: '',
    };
  }
  let breadcrumb = breadcrumbNameMap[url];
  if (!breadcrumb) {
    Object.keys(breadcrumbNameMap).forEach(item => {
      if (pathToRegexp(item).test(url)) {
        breadcrumb = breadcrumbNameMap[item];
      }
    });
  }
  return breadcrumb || { path: '' };
};

export const getBreadcrumbProps = (props: BreadcrumbProps): PageHeaderWrapperProps => {
  const { location, breadcrumbNameMap } = props;
  return {
    location,
    breadcrumbNameMap,
  };
};

// Generated according to props
const conversionFromProps = (props: BreadcrumbProps): AntdBreadcrumbProps['routes'] => {
  const { breadcrumbList = [] } = props;
  return breadcrumbList
    .map(item => {
      const { title, href } = item;
      return {
        path: href,
        breadcrumbName: title,
      };
    })
    .filter(item => item.path);
};

const conversionFromLocation = (
  routerLocation: PageHeaderWrapperProps['location'],
  breadcrumbNameMap: PageHeaderWrapperProps['breadcrumbNameMap'],
  props: BreadcrumbProps,
): AntdBreadcrumbProps['routes'] => {
  if (!routerLocation) {
    return [];
  }
  const { home } = props;
  // Convert the url to an array
  const pathSnippets = urlToList(routerLocation.pathname);
  // Loop data mosaic routing
  const extraBreadcrumbItems: AntdBreadcrumbProps['routes'] = pathSnippets
    .map(url => {
      const currentBreadcrumb = getBreadcrumb(breadcrumbNameMap, url);
      if (currentBreadcrumb.inherited) {
        return { path: '', breadcrumbName: '' };
      }
      const name = renderItemLocal(currentBreadcrumb);
      const { hideInBreadcrumb } = currentBreadcrumb;
      return name && !hideInBreadcrumb
        ? {
            path: url,
            breadcrumbName: name,
          }
        : { path: '', breadcrumbName: '' };
    })
    .filter(item => item && item.path);
  // Add home breadcrumbs to your head if defined
  if (home) {
    extraBreadcrumbItems.unshift({
      path: '/',
      breadcrumbName: home,
    });
  }
  return extraBreadcrumbItems;
};

/**
 * 将参数转化为面包屑
 * Convert parameters into breadcrumbs
 */
export const conversionBreadcrumbList = (props: BreadcrumbProps): AntdBreadcrumbProps => {
  const { breadcrumbList } = props;
  const { location, breadcrumbNameMap } = getBreadcrumbProps(props);
  if (breadcrumbList && breadcrumbList.length) {
    return {
      routes: conversionFromProps(props),
      itemRender,
    };
  }

  // 根据 location 生成 面包屑
  // Generate breadcrumbs based on location
  if (location && location.pathname) {
    return {
      routes: conversionFromLocation(location, breadcrumbNameMap, props),
      itemRender,
    };
  }
  return {
    routes: [],
  };
};