1. 程式人生 > >ant design pro 程式碼學習(二) ----- 路由資料分析

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’。

  • 方法引用:
 <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引數。

  •   其次,判斷是否有redirect引數,若有則將呼叫window.history.replaceState無重新整理狀態下更改url為localhost:8080/#/,也即路由為’/’,並返回redirect引數;如沒有redirect引數,則返回路由資訊中第一個已認證的路由,其中routerData是以路徑(path)為key的路由集合

      綜上所述,當路由path=’/’時,url中含有redirect引數時,重定向到redirect對應的路由元件;當不含redirect引數時,重定向到第一個已認證的路由元件。

7、 路由資料流程圖

這裡寫圖片描述