手擼Router,還要啥Router框架?react-router/vue-router躺一邊去

2022-09-05 18:01:23

有沒有發現,在大家使用React/Vue的時候,總離不開一個小尾巴,到哪都得帶著他,那就是react-router/vue-router,而基於它們的第三方框架又出現很多個性化約定和擴充套件,比如nuxtjs/nextjs/umijs都紛紛推出自己的路由方案。

有沒有想過,其實你可以完全擺脫他們都束縛?而且並不複雜,下面聽我來分析分析:

State可以控制一切UI

首先React/Vue都是基於MVVM架構,State可以決定Component的顯示與否,而且很簡單:

// jsx
{show? <SubUI /> : null}

// vue
<SubUI v-if="show" />

也可以根據State來動態顯示元件:

<component :is="componentA"></component>

控制UI的方法有很多,我就不例舉了,總之State才是掌控UI的大腦中樞。

將URL對映為State

路由的作用,無非就是根據Url來控制UI展示,那麼你只需要將Url對映成為State,不就達到目的了?

Url主要分2部分,pathnamequery,有很多第三方庫提供解析它們的方法,比如:

  • pathname解析:path-to-regexp
    const regexp = pathToRegexp("/:foo/:bar");
    regexp.exec("/test/route");
    
    具體用法大家看看官方檔案就可以了,很簡單...
  • query解析:query其實很靈活,沒有規定非得用什麼格式,最簡單的你直接用JSON.stringify將序列化後的字串作為query也可以,如果你想遵循常用的格式,你可以使用:query-string 或者 qs
    queryString.parse(location.search)
    

好了,現在你可以拿到解析Url後的資料,然後把它們轉換成你想要的State,存放在全域性Store中就可以了,比如你定義一個Url:

/member/list/3?uname=lily

//提取路由資訊
getRouteParams(): RouteParams {
    const query = queryString.parse(location.search);
    const [, curModule='', curView='', id=''] = pathToRegexp('/:curModule/:curView/:id')
    .exec(location.pathname) || [];
    if (curView === 'list') {
       //如果是列表,ID表示當前頁碼
       return {...query, pageCurrent: id, curView}
    } else if(curView === 'detail') {
       return {...query, id, curView}
    }
}

然後在UI中拿到這幾個State(可通過Redux或Vuex):

const Component = ({curView}) => {
  return (
    <>
      {curView === 'list' && <List />}
      {curView === 'detail' &&  <Detail />}
    </>
  );
};

發起路由跳轉

基於pushStatereplaceState,封裝一下就可以了:

window.history.pushState(null, '', url);
window.history.replaceState(null, '', url);
const Link = ({url, action, ...props}) => {
  const onClick = (event: MouseEvent) => {
    event.preventDefault();
    window.history[`${action}State`](null, '', url);
  }
  return <a onClick={onClick} {...props} />;
}

監聽路由變化

監聽popstate事件就行了:

window.addEventListener('popstate',() => {
  //解析Url並更新Store
  //...
});

手擼的好處

  • UI渲染更純粹,將UI的生殺大權牢牢掌握在State手中,UI = render(state),路由和其它因子都被擋在外圍,當作一種影響State的副作用之一。

  • 靈活性更高,你可以把URL對映成為任何State,從而控制任何State能控制的東西,比如用Url來控制一個按鈕的啟用與禁用,彈窗的彈出與關閉等等。
  • 不依賴各種第三方框架,不用學習它們,也不受它們的約束。
  • UI和Router之間沒有直接繫結,而是通過State對映,這意味著如果產品優化、路由格式變動,改動的只是對映,而不用動到View和State,這樣更鬆散。

實際案例

以上所說只是一個大體思路,真正要用得方便,還得做一些細節的封裝和改動,這裡提供一個自己的開源專案供大家參考,線上預覽:http://admin-react-antd.eluxjs.com/

該專案中,沒有使用任何第三方Router框架,全憑自己擼,那感覺也挺好的...