ant design pro 代码学习(二) ----- 路由数据分析

  本章节包含路由信息(common/router)、侧边栏菜单信息(common/menu)、基本路由(一级路由)UserLayout组件,BasicLayout组件、以及侧边栏SiderMenu组件中对数据的处理。主要涉及到以下几个方法,分别逐个分析其功能。

备注:本文中代码部分只截取涉及到的相关代码,完整代码请查看ant design Pro官方代码。

1、getMenuData:获取菜单配置数据

  对common/menu.js中定义的menuData数据做处理,如果path不是含有http的链接,即将path设置为完整的相对路径(即父菜单的路径 + 子菜单的路径),并获取当前菜单的权限,如果没有权限值,则继承父菜单的权限。其他相关属性(name、hideInMenu等)保持不变。

function formatter(data, parentPath = '/', parentAuthority) {
  return data.map(item => {
    let { path } = item;
    if (!isUrl(path)) {
      path = parentPath + item.path;
    }
    const result = {
      ...item,
      path,
      authority: item.authority || parentAuthority,
    };
    if (item.children) {
      result.children = formatter(item.children, `${parentPath}${item.path}/`, item.authority);
    }
    return result;
  });
}

export const getMenuData = () => formatter(menuData);

2、getFlatMenuData

   由1可知,menuData经过getMenuData()处理之后,path已经变成了完整的相对路径,getFlatMenuData主要是对getMenuData()的数据做处理。有如下使用方式,
getFlatMenuData有两个作用:
1. 将getMenuData()的结果(Array)转换成以path为key的对象数据(Object);
2. 通过递归调用,将getMenuData()的结果的父子层级结构的数据处理为平行数据。

  • 方法引用:
 const menuData = getFlatMenuData(getMenuData());
  • 方法定义:
function getFlatMenuData(menus) {
  let keys = {};
  menus.forEach(item => {
    if (item.children) {
      keys[item.path] = { ...item };
      keys = { ...keys, ...getFlatMenuData(item.children) };
    } else {
      keys[item.path] = { ...item };
    }
  });
  return keys;
}

3、 getRouterData:获取路由数据

   综合1、2可知,处理后的menuData是以path为key的Object,其中value为对应的菜单项配置。其中routerConfig为项目的路由配置,具体参看源代码。

  循环遍历routerConfig:
1. 当路由的path能在menuData中找到匹配(即菜单项对应的路由),则获取菜单项中当前path的配置menuItem;
2. 获取当前path的路由配置router;
3. 返回最新路由信息,name、authority、hideInBreadcrumb三个属性如果router中没有配置,则取菜单项中的配置。

export const getRouterData = app => {
  const routerConfig = {...};
  const menuData = getFlatMenuData(getMenuData());
  const routerData = {};

  Object.keys(routerConfig).forEach(path => {
    const pathRegexp = pathToRegexp(path);
    const menuKey = Object.keys(menuData).find(key => pathRegexp.test(`${key}`));
    let menuItem = {};

    if (menuKey) {
      menuItem = menuData[menuKey];
    }

    let router = routerConfig[path];

    router = {
      ...router,
      name: router.name || menuItem.name,
      authority: router.authority || menuItem.authority,
      hideInBreadcrumb: router.hideInBreadcrumb || menuItem.hideInBreadcrumb,
    };
    routerData[path] = router;
  });
  return routerData;
};

4、getRoutes:获取一级路由对应的路由数据

   用于获取当前路径对应的路由数据。共有几处使用该方法:

组件名称 match.path 父组件
BasicLayout /
UserLayout /user
StepForm /form/step-form BasicLayout
SearchList /list/search BasicLayout
  • 方法使用
{getRoutes(match.path, routerData).map(item => (...))}

   首先获取所有以path开头且路由不等于path的路由数据routes。getRenderArr(routes)对路由数据进行操作,过滤掉包含关系的路由。

   例如:当path=’/’时,’/list/search’、’/list/search/projects’、’/list/search/applications’、 ‘/list/search/articles’。这个四个路由信息存在包含关系。getRenderArr方法会将后三个过滤掉。渲染路由时,只生成’/list/search’对应的组件,也即SearchList。同时在SearchList中,调用getRoutes时,传入path=’ /list/search’,会从routerData筛选出’/list/search/projects’、’/list/search/applications’、 ‘/list/search/articles’这个三个路由的数据,并生成对应的Route组件。==此处/list/search可以理解为生成一个三级路由。==

  • 方法定义
export function getRoutes(path, routerData) {
  let routes = Object.keys(routerData).filter(
    routePath => routePath.indexOf(path) === 0 && routePath !== path
  );

  routes = routes.map(item => item.replace(path, ''));
  const renderArr = getRenderArr(routes);
  const renderRoutes = renderArr.map(item => {
    const exact = !routes.some(route => route !== item && getRelation(route, item) === 1);
    return {
      exact,
      ...routerData[`${path}${item}`],
      key: `${path}${item}`,
      path: `${path}${item}`,
    };
  });
  return renderRoutes==;==
}

该处源码存在两个小问题:
1. 当path=’/’时,当前进入了BasicLayout组件,getRoutes会返回含有/user的路由信息,会生成一个无效的路由?因为当路由为/user时,在一级路由的时候,已经被匹配了,就已经进入UserLayout,所以不可能在BasicLayout中出现匹配/user;
2. 过滤路由包含关系时,依赖其他routerConfig中出现的顺序,如上例,若调换’/list/search’、’/list/search/projects’在routerConfig中的顺序,则会出现404错误。因为此时/list/search/projects中不存在生成三级路由的代码。因此无法匹配路由,会出现404错误。此处需要注意路由配置的位置关系;


5、 getPageTitle:获取当前url对应的页面title

  此方法在UserLayout、BasicLayout组件中均有使用,通过获取路由信息中的name属性,动态的修改页面的title显示。其中DocumentTitle引用’react-document-title’。

扫描二维码关注公众号,回复: 2202870 查看本文章
  • 方法引用:
 <DocumentTitle title={this.getPageTitle()}>
...
</DocumentTitle>
  • 方法定义:
  getPageTitle() {
    const { routerData, location } = this.props;
    const { pathname } = location;
    let title = 'Ant Design Pro';
    if (routerData[pathname] && routerData[pathname].name) {
      title = `${routerData[pathname].name} - Ant Design Pro`;
    }
    return title;
  }

6、 getBashRedirect:BasicLayout下路由重定向

  此方法在BasicLayout组件中使用,用来设置路由为’/’时,重定向的路径。

  • 方法引用:

    // BasicLayout.js
    const bashRedirect = this.getBashRedirect();
    ...
    <Content style={{ margin: '24px 24px 0', height: '100%' }}>
    ...
      <Redirect exact from="/" to={bashRedirect} />
      <Route render={NotFound} />
    </Switch>
    </Content>
  • 方法定义:

    // BasicLayout.js
    getBashRedirect = () => {
        const urlParams = new URL(window.location.href);
        const redirect = urlParams.searchParams.get('redirect');
        // Remove the parameters in the url
        if (redirect) {
          urlParams.searchParams.delete('redirect');
          window.history.replaceState(null, 'redirect', urlParams.href);
        } else {
          const { routerData } = this.props;
          // get the first authorized route path in routerData
          const authorizedPath = Object.keys(routerData).find(
            item => check(routerData[item].authority, item) && item !== '/'
          );
          return authorizedPath;
        }
        return redirect;
      };

      首先,获取url中redirect参数,这里的参数指的是url中search参数,而并非hash参数。如下例所以,第一个url能即为search参数,第二个url即为hash参数。

  • http://localhost:8000/?redirect=/result/success
  • http://localhost:8000/#/?redirect=result/success

      其次,判断是否有redirect参数,若有则将调用window.history.replaceState无刷新状态下更改url为localhost:8080/#/,也即路由为’/’,并返回redirect参数;如没有redirect参数,则返回路由信息中第一个已认证的路由,其中routerData是以路径(path)为key的路由集合

      综上所述,当路由path=’/’时,url中含有redirect参数时,重定向到redirect对应的路由组件;当不含redirect参数时,重定向到第一个已认证的路由组件。

7、 路由数据流程图

这里写图片描述


上一篇:ant design pro 代码学习(一) —– 路由分析
下一篇:ant design pro 代码学习(三) —– 菜单数据分析


猜你喜欢

转载自blog.csdn.net/zcs425171513/article/details/80737431