關於 前端路由復用策略網上的文章很多,大多是講如何實現tab標簽切換歷史數據,至於如何復用的原理講的都比較朦朧,代碼樣例也很難適用各種各樣的路由配置,比如懶加載模式下多級嵌套路由出口網上的大部分代碼都會報錯。
我希望能通過這篇文章把如何復用路由的原理講明白,讓小伙伴能明明白白的實用路由復用策略,文字中有不詳實和錯誤的地方歡迎小伙伴批評指正
對路由復用策略的理解
路由復用策略的是對路由的父級相同節點的組件實例的復用,我們平時看到的多級嵌套路由切換時上層路由出口的實例並不會從新實例化就是因為angular默認的路由復用策略在起作用,而我們從寫路由復用策略能實現很多事情,其中之一就是實現
歷史路由狀態(數據)的存儲,即jquery時代的tab頁簽和iframe實現操作歷史的切換。
我一開始認為路由復用策略就是對歷史路由數據的復用策略,這個錯誤的觀念導致我對路由復用策略接口方法理解起來異常困難,不知小伙伴和我犯沒犯同樣的錯誤。觀念正確了,下面就理解起來比較方便了,寫路由復用策略也就比較順手了。
下面是angular默認路由復用策略,每切換一下路由,下面代碼都再默默的執行。
export class DefaultRouteReuseStrategy {
shouldDetach(route) { return false; }
store(route, detachedTree) { }
shouldAttach(route) { return false; }
retrieve(route) { return null; }
shouldReuseRoute(future, curr) {
return future.routeConfig === curr.routeConfig;
}
}
關鍵概念解釋
開始文章前我們先了解幾個觀念概念
- 我們的路由是棵樹,
RouterModule.forRoot(Routes)
,RouterModule.forChild(Routes)
這些配置最后形成一個完整的路由樹,路由樹有個根是沒有routeConfig
的,routeConfig
是我們寫的每個route
。 - 路由節點,一個路徑是由幾個路由節點組成,有的
route
配置了component,有的則沒有 - future下一路由, curr當前路由,切換路由時,我們在下文用future表示下一路由,curr表示當前路由
路由復用策略解析
路由復用策略方法調用順序
shouldReuseRoute(future, curr)
retrieve(route)
shouldDetach(route)
store(route, detachedTree)
shouldAttach(route)
-
retrieve
,取決一上一步的返回值 -
store(route, detachedTree)
,取決第五步
shouldReuseRoute
shouldReuseRoute()
決定是否復用路由,根據切換的future
curr
的節點層級依次調用,返回值為true時表示當前節點層級路由復用,然后繼續下一路由節點調用,入參為切換的下一級路由(子級)的future
curr
路由的節點,返回值為false時表示不在復用路由,並且不再繼續調用此方法(future
路由不再復用,其子級路由也不會復用,所以不需要再詢問下去),root路由節點調用一次,非root路由節點調用兩次這個方法,第一次比較父級節點,第二次比較當前節點,
retrieve
retrieve()
接上一步奏,當當前層級路由不需要復用的時候,調用一下retrieve
方法,其子級路由也會調用一下retrieve
方法,如果返回的是null,那么當前路由對應的組件會實例化,這種行為一直持續到末級路由。
shouldDetach
shouldDetach
是對上一路由的數據是否實現拆離,其調用開始是當前層級路由不需要復用的時候,即shouldReuseRoute()
返回false的時候,如果這時候反回false,將繼續到上一路由的下一層級調用shouldDetach
,直到返回true或者是最末級路由后才結束對shouldDetach
的調用,當返回true時就調用一次store
方法,請看下一步奏
store
store
存儲路分離出來的上一路由的數據,當 shouldDetach
返回true時調用一次,存儲應該被分離的那一層的路由的DetachedRouteHandle
。注意:無論路由樹上多個含有組件component
路由節點,能分離出來的只能有一個,被存儲的也只能有一個,感覺這種機制對使用場景有很大限制。
shouldAttach
shouldAttach
是對當前路由的數據是否實現恢復(附加回來),其調用開始是當前層級路由不需要復用的時候,即shouldReuseRoute()
返回false的時候,這和shouldDetach
的調用時機很像,但是,並不是所有的路由層級都是有組件實例的,只有包含component
的route
才會觸發shouldAttach
,如果反回false,將繼續到當前路由的下一帶有component
的路由層級調用shouldAttach
,直到返回true或者是最末級路由后才結束對shouldAttach
的調用,當返回true時就調用一次retrieve
方法,如果retrieve
方法去獲取一下當前路由的DetachedRouteHandle
,返回一個DetachedRouteHandle
,就再調用一次store
,再保存一下retrieve
返回的DetachedRouteHandle
。注意注意:無論路由樹上多個含有組件component
路由節點,能恢復數據的只能有一個節點,這和shouldDetach
是一個套路,對使用場景有很大限制。
總結·這個還是實驗性的路由復用策略還是不夠強大
路由復用策略這種調用機制對使用場景限制很大 ,比如多級路由出口嵌套就無法實現路由數據緩存。因為多級路由出口嵌套的應用切換路由時,前后路由會包含多個帶component的路由節點,而每次對路由的存儲和恢復只能存儲和恢復某一個節點的component的DetachedRouteHandle
,其他路由節點上的component就是被從新實例化。明白這一點后我就放棄了想寫一個可以適用任何場景的路由復用策略的想法,如果有小伙伴能解決好這一業務場景,歡迎賜教。
如果這個路由復用策略可以存儲一個路由上多個節點的DetachedRouteHandle
,和恢復多個節點的DetachedRouteHandle
,應該能解決上面是的多級路由出口嵌套場景,但不知道會不會帶來別的問題。
一個路由復用策略用例
下面貼一個路由復用策略用例,應該是滿足大部分人的業務要求,注意事項:只能是末級路由的緩存,且路由切換的時候路由節點上的component不能超過兩個。
import {ActivatedRouteSnapshot, DetachedRouteHandle, Route, RouteReuseStrategy} from "@angular/router";
export class CustomerReuseStrategy implements RouteReuseStrategy {
static handlers: Map<Route, DetachedRouteHandle> = new Map();
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return !route.firstChild;
}
shouldAttach(route: ActivatedRouteSnapshot): boolean {
return !!CustomerReuseStrategy.handlers.has(route.routeConfig);
}
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot) {
return curr.routeConfig === future.routeConfig;
}
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
return CustomerReuseStrategy.handlers.get(route.routeConfig);
}
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
CustomerReuseStrategy.handlers.set(route.routeConfig, handle);
}
}
很精簡,但是很好用,小伙伴可以根據自己的業務邏輯進行改造。
如果感覺這篇文章對你有幫助,請點個贊吧 👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍