有沒有發現,在大家使用React/Vue的時候,總離不開一個小尾巴,到哪都得帶著他,那就是react-router/vue-router,而基於它們的第三方框架又出現很多個性化約定和擴展,比如nuxtjs/nextjs/umijs都紛紛推出自己的路由方案。 ...
有沒有發現,在大家使用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部分,pathname
和query
,有很多第三方庫提供解析它們的方法,比如:
- 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 />}
</>
);
};
發起路由跳轉
基於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渲染更純粹,將UI的生殺大權牢牢掌握在State手中,
UI = render(state)
,路由和其它因數都被擋在外圍,當作一種影響State的副作用之一。
- 靈活性更高,你可以把URL映射成為任何State,從而控制任何State能控制的東西,比如用Url來控制一個按鈕的啟用與禁用,彈窗的彈出與關閉等等。
- 不依賴各種第三方框架,不用學習它們,也不受它們的約束。
- UI和Router之間沒有直接綁定,而是通過State映射,這意味著如果產品優化、路由格式變動,改動的只是映射,而不用動到View和State,這樣更鬆散。
實際案例
以上所說只是一個大體思路,真正要用得方便,還得做一些細節的封裝和改動,這裡提供一個自己的開源項目供大家參考,線上預覽:http://admin-react-antd.eluxjs.com/
該項目中,沒有使用任何第三方Router框架,全憑自己擼,那感覺也挺好的...