關於路由複用策略網上的文章不少,大可能是講如何實現tab標籤切換歷史數據,至於如何複用的原理講的都比較朦朧,代碼樣例也很難適用各類各樣的路由配置,好比懶加載模式下多級嵌套路由出口網上的大部分代碼都會報錯。
我但願能經過這篇文章把如何複用路由的原理講明白,讓小夥伴能明明白白的實用路由複用策略,文字中有不詳實和錯誤的地方歡迎小夥伴批評指正
路由複用策略的是對路由的父級相同節點的組件實例的複用,咱們平時看到的多級嵌套路由切換時上層路由出口的實例並不會重新實例化就是由於angular默認的路由複用策略在起做用,而咱們從寫路由複用策略能實現不少事情,其中之一就是實現
歷史路由狀態(數據)的存儲,即jquery時代的tab頁籤和iframe實現操做歷史的切換。jquery
我一開始認爲路由複用策略就是對歷史路由數據的複用策略,這個錯誤的觀念致使我對路由複用策略接口方法理解起來異常困難,不知小夥伴和我犯沒犯一樣的錯誤。觀念正確了,下面就理解起來比較方便了,寫路由複用策略也就比較順手了。緩存
下面是angular默認路由複用策略,每切換一下路由,下面代碼都再默默的執行。code
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,有的則沒有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路由節點調用兩次這個方法,第一次比較父級節點,第二次比較當前節點,component
retrieve
retrieve()
接上一步奏,噹噹前層級路由不須要複用的時候,調用一下retrieve
方法,其子級路由也會調用一下retrieve
方法,若是返回的是null,那麼當前路由對應的組件會實例化,這種行爲一直持續到末級路由。router
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
是一個套路,對使用場景有很大限制。get
路由複用策略這種調用機制對使用場景限制很大 ,好比多級路由出口嵌套就沒法實現路由數據緩存。由於多級路由出口嵌套的應用切換路由時,先後路由會包含多個帶component的路由節點,而每次對路由的存儲和恢復只能存儲和恢復某一個節點的component的DetachedRouteHandle
,其餘路由節點上的component就是被重新實例化。明白這一點後我就放棄了想寫一個能夠適用任何場景的路由複用策略的想法,若是有小夥伴能解決好這一業務場景,歡迎賜教。 iframe
若是這個路由複用策略能夠存儲一個路由上多個節點的DetachedRouteHandle
,和恢復多個節點的DetachedRouteHandle
,應該能解決上面是的多級路由出口嵌套場景,但不知道會不會帶來別的問題。class
下面貼一個路由複用策略用例,應該是知足大部分人的業務要求,注意事項:只能是末級路由的緩存,且路由切換的時候路由節點上的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 { if (!!route.firstChild) { return null; } return CustomerReuseStrategy.handlers.get(route.routeConfig); } store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void { CustomerReuseStrategy.handlers.set(route.routeConfig, handle); } }
很精簡,可是很好用,小夥伴能夠根據本身的業務邏輯進行改造。
若是感受這篇文章對你有幫助,請點個贊吧 👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍