Loading

适用于react、vue菜单格式化工具函数

场景

在一个动态菜单场景中,你向接口获取树形菜单,但最后拿到的树未能达到你的预期,这个时候就需要手写递归重新处理这颗树

适用于react、vue菜单格式化工具函数

包含功能

1. 当前路由是否存在返回按钮

判断逻辑:只要存在左侧可点击的菜单都不具备返回按钮,其他则具有返回按钮

2. 错误路由过滤提醒

假设有这么一个菜单

const router = [
  {
    path: '/test',
    children: [
      {
        path: '/test/page2',
      },
      {
        path: '/otest/page2',
      },
    ],
  },
];

可以看到`/otest/page2`属于无效路由,在react中,这可是致命错误,将破环整个项的运行

这个工具则可以过滤出这种错误路由,并且给出对应提示

3. 递归获取当前菜单下的可用路由

 

解释一下这种布局,顶部一级菜单,左侧二级菜单

当用户点击顶部菜单时,展示左侧菜单并选中第一个二级可用菜单,正常情况下其实用户点击了顶部菜单是无法知道二级菜单哪个菜单是可用的

因为二级里面还包含二级,正常应该获取二级菜单里面存在组件的菜单

 

上工具代码

/**
 * @desc 获取动态菜单中第一项可用菜单
 * 正常情况第一项可用菜单就是路由第一个路由中的二层嵌套的第一项菜单
 * */

export const firstAvailableRouter = (routes) => {
  const [router] = routes;
  if (!router?.component && router?.children?.length && !router.redirect) {
    return firstAvailableRouter(router.children);
  } else {
    return router;
  }
};

/**
 *  格式化菜单树
 * @param tree {Array} 树形菜单
 * @param parent {Array} 递归时做为临时存储用
 * */
export const formatTreeMenu = ({
  tree = [],
  parent = []
}: {
  tree: Record<string, any>[];
  parent?: Record<string, any>;
}) => {
  if (!tree || !Array.isArray(tree)) {
    return [];
  }
  /** 先检查所有子集是否都满足要求 */
  const filteredTree = tree
    .filter((item) => item.path)
    .filter((item) => {
      const parentPath = parent.path || '/';
      const hasErrorRouter = parentPath && !item.path.startsWith(parentPath);
      if (hasErrorRouter) {
        console.warn(`路由:'${item.path}'配置错误,已被过滤`);
      }
      return !hasErrorRouter;
    });
  return filteredTree.map((node) => {
    const {
      title,
      layout = undefined,
      routes,
      hideInMenu = false,
      path,
      icon,
      component,
      id
    } = node;
    const hasBack = parent.path === path ? parent.hideInMenu : hideInMenu;
    const firstUsefulRoute =
      firstAvailableRouter({ routes, childrenKye: 'routes' }) || {};
    const formattedNode: Record<string, any> = {
      path,
      name: title,
      layoutWrap: layout,
      hideInMenu,
      roles: ['admin'],
      hasBack,
      component,
      id,
      firstUsefulRoute //第一个有用路由
    };
    if (icon) {
      formattedNode.icon = icon;
    }
    if (Array.isArray(routes) && routes.length > 0) {
      formattedNode.children = formatTreeMenu({
        tree: routes,
        parent: node
      });
    }
    return formattedNode;
  });
};

 

测试数据

const router = [
  {
    name: 'portalRegist',
    path: '/portalRegist',
    hideInMenu: true,
    layout: false,
    component: './pages/Portal/regist',
    children: [
      {
        path: './',
        redirect: 'readme',
      },
      {
        path: '/portalRegist/:id',
        component: './pages/Portal/regist/readme',
      },
      {
        name: 'portalReadme',
        path: '/portalRegist/readme/:id',
        component: './pages/Portal/regist/readme',
      },
      {
        name: 'portalAuth',
        path: '/portalRegist/auth/:id',
        component: './pages/Portal/regist/auth',
      },
    ],
  },
  {
    path: '/carbon/greenCompliance/energyUsage',
    name: 'xx',
    component: './pages/GreenCompliance/EnergyUsage',
    hideInMenu: true,
  },
];

 

posted @ 2024-07-12 15:51  冯叶青  阅读(1)  评论(0编辑  收藏  举报