有沒有發現,在大家使用React/Vue的時候,總離不開一個小尾巴,到哪都得帶著他,那就是react-router/vue-router,而基於它們的第三方框架又出現很多個性化約定和擴充套件,比如nuxtjs/nextjs/umijs都紛紛推出自己的路由方案。
有沒有想過,其實你可以完全擺脫他們都束縛?而且並不複雜,下面聽我來分析分析:
首先React/Vue都是基於MVVM架構,State可以決定Component的顯示與否,而且很簡單:
// jsx
{show? <SubUI /> : null}
// vue
<SubUI v-if="show" />
也可以根據State來動態顯示元件:
<component :is="componentA"></component>
控制UI的方法有很多,我就不例舉了,總之State才是掌控UI的大腦中樞。
路由的作用,無非就是根據Url來控制UI展示,那麼你只需要將Url對映成為State,不就達到目的了?
Url主要分2部分,pathname
和query
,有很多第三方庫提供解析它們的方法,比如:
const regexp = pathToRegexp("/:foo/:bar");
regexp.exec("/test/route");
具體用法大家看看官方檔案就可以了,很簡單...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 />}
</>
);
};
基於pushState
和replaceState
,封裝一下就可以了:
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 = render(state)
,路由和其它因子都被擋在外圍,當作一種影響State的副作用之一。以上所說只是一個大體思路,真正要用得方便,還得做一些細節的封裝和改動,這裡提供一個自己的開源專案供大家參考,線上預覽:http://admin-react-antd.eluxjs.com/
該專案中,沒有使用任何第三方Router框架,全憑自己擼,那感覺也挺好的...