單頁面應用現在是主流,隨之而來的缺點:頁面間切換時不能保存狀態
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()方法
