Skip to content

面包屑导航 ​

修改app.tsx文件 ​

tsx
// 运行时配置
import routes from "@/config/routes";
import mockMenuData from "@/mock/data";

type RouteConfig = {
  path?: string;
  name?: string;
  routes?: RouteConfig[];
};

// 从路由配置中递归提取 路径 -> 菜单名称 映射
function buildMenuNameMap(routes: RouteConfig[] = []): Record<string, string> {
  const map: Record<string, string> = {};
  routes.forEach((route) => {
    if (route.path && route.name) {
      map[route.path.replace(/^\//, "")] = route.name.trim();
    }
    if (route.routes) {
      Object.assign(map, buildMenuNameMap(route.routes));
    }
  });
  return map;
}

const menuNameMap = buildMenuNameMap(routes as RouteConfig[]);

// 收集所有"有子路由"的路径(来自路由配置),用于面包屑判断
const parentPaths = new Set<string>();
(function collectParents(list: RouteConfig[] = []) {
  list.forEach((r) => {
    if (r.routes && r.routes.length > 0 && r.path) {
      parentPaths.add(r.path);
      collectParents(r.routes);
    }
  });
})(routes as RouteConfig[]);

type MenuItem = {
  path: string;
  name: string;
  children?: MenuItem[];
};

// 将平铺的路径数组转换为菜单树
function buildMenu(paths: string[]): MenuItem[] {
  const root: MenuItem[] = [];
  const nodeMap = new Map<string, MenuItem>();

  paths.forEach((p) => {
    const segments = p.split("/");
    let parentChildren = root;
    let currentPath = "";

    segments.forEach((seg, idx) => {
      currentPath = currentPath ? `${currentPath}/${seg}` : seg;
      let node = nodeMap.get(currentPath);
      if (!node) {
        node = {
          path: `/${currentPath}`,
          name: menuNameMap[currentPath] || seg,
        };
        nodeMap.set(currentPath, node);
        parentChildren.push(node);
      }
      if (idx < segments.length - 1) {
        node.children = node.children || [];
        parentChildren = node.children;
      }
    });
  });

  return root;
}

// 全局初始化数据配置,用于 Layout 用户信息和权限初始化
// 更多信息见文档:https://umijs.org/docs/api/runtime-config#getinitialstate
export async function getInitialState(): Promise<{ name: string }> {
  return { name: "@umijs/max" };
}

export const layout = () => {
  return {
    logo: "https://img.alicdn.com/tfs/TB1YHEpwUT1gK0jSZFhXXaAtVXa-28-27.svg",
    menu: {
      locale: false,
      // 从 mock 数据动态生成菜单
      request: async () => buildMenu(mockMenuData),
    },
    // 开启面包屑导航
    breadcrumbRender: (routers = []) => {
      return [
        {
          path: "/home",
          breadcrumbName: "首页",
        },
        ...routers,
      ];
    },
    // 自定义面包屑项渲染:路径属于父路由(有子路由)时渲染为纯文本
    itemRender: (route: any) => {
      const isParent = route.path && parentPaths.has(route.path);
      return isParent ? (
        <span>{route.breadcrumbName}</span>
      ) : (
        <a href={route.path}>{route.breadcrumbName}</a>
      );
    },
  };
};