單頁面應用現在是主流,隨之而來的缺點:頁面間切換時不能保存狀態
angular4出了一個RouteReuseStrategy路由重用策略可以讓組件所有的state和渲染好的html存起來,然后在切回去的時候再調出來。
export declare abstract class RouteReuseStrategy{ abstract shouldReuseRoute():Boolean abstract shouldAttach():Boolean abstract retrieve():DetachedRouteHandle | null abstract shouldDetach():Boolean abstract store():void }
替換一旦發生,某些組件將被丟棄
這時shouldDetech,store將被調用,用於緩存即將被丟棄的組件
有組件丟棄,自然有組件替補進來
這時shouldAttach retreive將被調用,用於調出緩存的組件
🌊 應用場景
1.進入某個路由頁面,進行操作,切換頁面再返回,能還原到之前的操作狀態;
2.切換右邊的tab,能進入到對應的路由頁面(操作后的狀態);
3.點擊右邊tab里的關閉按鈕或頁面上的關閉按鈕,刪除某個路由頁面的快照,再次點開這個路由頁面,頁面恢復初始狀態;
🌊 下面是具體實現
要注意的點:
1. store方法:存儲上一個頁面的快照
2.關閉路由有幾種情況:
i 打開A頁面后 打開B頁面 關閉B頁面(此時B頁面沒有快照) -> 觸發store方法
ii 打開A頁面后 打開B頁面 關閉A頁面 (此時A頁面有快照) -> 不觸發store方法
iii 打開A頁面后 打開B頁面 回到A頁面 關閉A頁面 (此時A頁面有快照) ->不觸發store方法
iii 打開A頁面后 打開B頁面 回到A頁面 關閉B頁面 (此時B頁面有快照) ->不觸發store方法
因此頁面在沒有快照的時候關閉 需要在store方法里做一個暫緩刪除的操作(先記錄key 進去新頁面后 再刪除key)
這樣頁面的ngOnDestroy()方法才能執行 才能避免事件重復監聽(在ngOnDestroy()中執行)
相關的知識點:
ActivatedRouteSnapshot:包含當前插座中加載組件某一特定時間路由信息
RouteReuseStrategy:路由復用策略
DetachedRouteHandle:組件當前所有狀態(路由快照
import {ActivatedRouteSnapshot, RouteReuseStrategy, DetachedRouteHandle} from '@angular/router; export class ExtensionRouteReuseStrategy implements RouteReuseStrategy { private static waitDelete:string; public static storedRoutes: Map<string, DetachedRouteHandle> = new Map<string, DetachedRouteHandle>(); constructor(){ //關閉操作(右上角或者history頁面) this.storageNotifyRouter.destoryTopic.subscribe((key) => { this.processDestory(key); }); }; //是否緩存【離開路由時觸發】 shouldDetach(route: ActivatedRouteSnapshot): boolean { if (route.data && route.data.key) { return true; } return false; } //緩存組件【離開路由時觸發】 store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void { const key = this.findStoreKey(route); const key$$ = this.lastClosedKey + _SPLIT; //未存儲快照的情況下 跳轉新頁面 再刪key if (this.waitDeleteRoutes.size > 0) { const array = Array.from(this.waitDeleteRoutes.keys()); for (const deletekey of array) { if (deletekey == key) { const oldHandle = handle as { componentRef: ComponentRef<any> }; oldHandle.componentRef.destroy(); } this.waitDeleteRoutes.delete(deletekey); } return; } //存儲上一個頁面快照 進入新頁面 if (handle && !(key === this.lastClosedKey || key.startsWith(key$$))) { this.lastClosedKey = ''; this.storedRoutes.set(key, handle); } } //是否還原【進入路由時觸發】 shouldAttach(route: ActivatedRouteSnapshot): boolean { const key = this.findRetrieveKey(route); const result: boolean = !!key && !!this.storedRoutes.get(key); return result; } //還原路由【進入路由時觸發】 retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle { const key = this.findRetrieveKey(route); let handle = null; if (key && this.storedRoutes.get(key)) { handle = this.storedRoutes.get(key); this.routerNotifyStorage.notifyRetrieve(key); } return handle; } //是否復用路由【進入路由時觸發】 shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { const result: boolean = future.routeConfig === curr.routeConfig; return result; } findStoreKey(route: ActivatedRouteSnapshot): string { let key = ""; if (route.data && route.data.key) { if (route.children[0] && route.children[0].data && route.children[0].data.key) { this.findStoreKey(route.children[0]); } else { key = route.data.key; } } return key; } findRetrieveKey(route: ActivatedRouteSnapshot): string { let key = ""; if (route.data && route.data.key) { key = route.data.key; } return key; } processDestory(key: string, waiteDelete: boolean = true) { this.lastClosedKey = key; let existKey: boolean = false; const array: string[] = Array.from(this.storedRoutes.keys()); for (const keyStored of array) { const key$$ = key + _SPLIT; //存儲快照的情況下 刪除快照 if (key === keyStored || keyStored.startsWith(key$$)) { const oldHandle = this.storedRoutes.get(keyStored) as { componentRef: ComponentRef<any> }; oldHandle.componentRef.destroy(); this.storedRoutes.delete(keyStored); existKey = true; } } //未存儲快照 先存當前頁面key if (!existKey && waiteDelete) { this.waitDeleteRoutes.add(key); } } }
🌊 后續
保存快照
在離開路由時保存上一個頁面快照,並emit一個事件給左邊的菜單組件和右邊的tab組件,告訴它們路由路徑已改變,同時把新的路由路徑作為參數傳過去
然后在左邊的菜單組件和右邊的tab組件里subscribe事件里去監聽變化,替換新的路由路徑。
這樣在點擊它們的時候就會重定向到新的路由路徑,而快照已保存。
刪除快照
在點擊右邊tab組件里的關閉按鈕或者點擊頁面上的關閉按鈕時,emit一個刪除快照的事件,同時把路由路徑作為參數傳過去
然后在路由復用策略的ts文件中的subscribe事件里去監聽這個事件,然后執行對應路由的processDestroy()方法