angular 路由复用策略

最近在弄单页面组件刷新功能的时候,接触到路由复用策略,总结下:
用法:

  • 新建路由复用文件 SimpleReuseStrategy.ts:
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];
      }
    }
  }

}

  • 在AppModule中引入该文件:
@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方法,如:

你可能感兴趣的:(angular)