最近在弄单页面组件刷新功能的时候,接触到路由复用策略,总结下:
用法:
import { RouteReuseStrategy, DefaultUrlSerializer, ActivatedRouteSnapshot, DetachedRouteHandle } from '@angular/router';
// import { compact } from 'rxjs';
import { ComponentRef } from '@angular/core';
export class SimpleReuseStrategy implements RouteReuseStrategy {
public static handlers: { [key: string]: DetachedRouteHandle } = {};
private static getRouteUrl(route: ActivatedRouteSnapshot) {
return route['_routerState'].url.replace(/[\/, -]/g, '_');
}
/** 表示对所有路由允许复用 如果你有路由不想利用可以在这加一些业务逻辑判断 */
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
return !(!route.routeConfig || route.routeConfig.loadChildren);
}
/** 当路由离开时会触发。按path作为key存储路由快照&组件当前实例对象 */
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
SimpleReuseStrategy.handlers[SimpleReuseStrategy.getRouteUrl(route)] = handle;
}
/** 若 path 在缓存中有的都认为允许还原路由 */
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
return !!route.routeConfig && !!SimpleReuseStrategy.handlers[SimpleReuseStrategy.getRouteUrl(route)];
}
/** 从缓存中获取快照,若无则返回nul */
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
if (!route.routeConfig || route.routeConfig.loadChildren) {
return null;
}
// console.log(SimpleReuseStrategy.handlers);
return SimpleReuseStrategy.handlers[SimpleReuseStrategy.getRouteUrl(route)];
}
/** 进入路由触发,判断是否同一路由 */
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
/** 清除缓存 */
public clearCacheHandle(){
for (const key in SimpleReuseStrategy.handlers) {
if (SimpleReuseStrategy.handlers[key]){
this.deactivateOutlet(SimpleReuseStrategy.handlers[key])
}
}
}
/** 处理同一组件不同链接的问题 */
private deactivateOutlet(handle: DetachedRouteHandle): void {
const componentRef: ComponentRef = handle ? handle['componentRef'] : null;
if (componentRef) {
componentRef.destroy();
}
}
public clearCacheByUrl(url: string){
const handleUrl = url.replace(/[\/, -]/g, '_');
for (const key in SimpleReuseStrategy.handlers) {
if (key === handleUrl){
delete SimpleReuseStrategy.handlers[key];
}
}
}
}
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
DelonModule.forRoot(),
CoreModule,
SharedModule,
LayoutModule,
RoutesModule,
...I18NSERVICE_MODULES,
...GLOBAL_THIRD_MODULES,
...FORM_MODULES,
// ...MOCKMODULE,
// TreeviewModule.forRoot(),
],
providers: [...LANG_PROVIDES, ...INTERCEPTOR_PROVIDES, ...I18NSERVICE_PROVIDES, ...APPINIT_PROVIDES, ApiService, LogService,
// { provide: RouteReuseStrategy, useClass: ReuseTabStrategy, deps: [ ReuseTabService] },
{ provide: RouteReuseStrategy, useClass: SimpleReuseStrategy },
],
bootstrap: [AppComponent],
})
export class AppModule {}
现在复用策略已经生效,这里主要说下配置过程中遇到的问题:
1、Cannot reattach ActivatedRouteSnapshot created from a different route
解决办法:
替换shouldDetach和retrieve方法如下(必须同时替换):
/** 表示对所有路由允许复用 如果你有路由不想利用可以在这加一些业务逻辑判断 */
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
if (!route.routeConfig || route.routeConfig.loadChildren) {
return false;
}
return true;
}
/** 从缓存中获取快照,若无则返回nul */
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
if (!route.routeConfig) {
return null;
}
if(route.routeConfig.loadChildren) return null;
return SimpleReuseStrategy.handlers[SimpleReuseStrategy.getRouteUrl(route)];
}
2、路由复用策略中的store方法,必须是一下两种方式引起的路由跳转才会触发:
(1):
(2):由router类发起的路由跳转,如:router.navigate()或router.navigateByUrl等
如果是直接指令方式发起的则不会触发store方法,如: