Angular2 无法使用延迟模块加载的自定义重用策略

Posted

技术标签:

【中文标题】Angular2 无法使用延迟模块加载的自定义重用策略【英文标题】:Angular2 doesn't work Custom Reuse Strategy with Lazy module loading 【发布时间】:2017-07-12 00:48:12 【问题描述】:

我尝试在我的 angular2 项目中使用custom reuse strategy, 但我发现它不适用于 延迟模块加载。 有谁知道这件事吗?我的项目是 angular 2.6.4

重用策略.ts

import RouteReuseStrategy, ActivatedRouteSnapshot, DetachedRouteHandle from "@angular/router";

export class CustomReuseStrategy implements RouteReuseStrategy 

    handlers: [key: string]: DetachedRouteHandle = ;

    shouldDetach(route: ActivatedRouteSnapshot): boolean 
        console.debug('CustomReuseStrategy:shouldDetach', route);
        return true;
    

    store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void 
        console.debug('CustomReuseStrategy:store', route, handle);
        this.handlers[route.routeConfig.path] = handle;
    

    shouldAttach(route: ActivatedRouteSnapshot): boolean 
        console.debug('CustomReuseStrategy:shouldAttach', route);
        return !!route.routeConfig && !!this.handlers[route.routeConfig.path];
    

    retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle 
        console.debug('CustomReuseStrategy:retrieve', route);
        if (!route.routeConfig) return null;
        return this.handlers[route.routeConfig.path];
    

    shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean 
        console.debug('CustomReuseStrategy:shouldReuseRoute', future, curr);
        return future.routeConfig === curr.routeConfig;
    


app.module.ts

const appRoutes: Routes = [
   path: 'crisis-center', component: CrisisListComponent ,
   path: 'heroes', loadChildren: 'app/hero-list.module#HeroListModule' ,
   path: '',   redirectTo: '/crisis-center', pathMatch: 'full' 
];
@NgModule(
  imports: [ ... ],
  declarations: [ ... ],
  providers:[
    provide: RouteReuseStrategy, useClass: CustomReuseStrategy
  ],
  bootstrap: [ AppComponent ]
)
export class AppModule  

然后我将<input> 放入两个组件并对其进行了测试。

CrisisListComponent 中的输入值被存储,但HeroListComponent lazy-loaded 的值没有被保留。

我不知道它还不支持。 谢谢你帮助我。

【问题讨论】:

【参考方案1】:

RouteReuseStrategy 确实适用于 LazyLoaded 组件。

这里的问题是您使用route.routeConfig.path 作为存储和检索句柄的密钥。

我不知道为什么,但是对于 LazyLoaded 模块,在执行 shouldAttach 时,route.routeConfig.path 是空的

我使用的解决方案是在我的路由中定义一个自定义键,例如:

 path: '...', loadChildren: '...module#...Module', data:  key: 'custom_key'  

这个键值在ActivatedRouteSnapshot中可以很方便的访问,比如:

route.data.key

使用此密钥,您可以正确存储和检索句柄。

【讨论】:

【参考方案2】:

使用这个。它使用组件名称作为键来存储和检索句柄。

import ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy from '@angular/router';

export class CustomReuseStrategy implements RouteReuseStrategy 


  handlers:  [key: string]: DetachedRouteHandle  = ;


  shouldDetach(route: ActivatedRouteSnapshot): boolean 
    return true;
  

  store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void 
    this.handlers[this.getKey(route)] = handle;
  

  shouldAttach(route: ActivatedRouteSnapshot): boolean 
    return !!route.routeConfig && !!this.handlers[this.getKey(route)];
  

  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle 
    if (!route.routeConfig) 
      return null;
    
    return this.handlers[this.getKey(route)];
  

  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean 
    return curr.routeConfig === future.routeConfig;
  

  private getKey(route: ActivatedRouteSnapshot) 
    let key: string;
    if (route.component) 
      key = route.component['name'];
     else 
      key = route.firstChild.component['name'];
    
    return key;
  


【讨论】:

【参考方案3】:

要使其正常工作,您应该考虑完整路径,而不是大多数文章建议的简单 route.routeConfig.path。例如:

private getKey(route: ActivatedRouteSnapshot): string 
    return route.pathFromRoot
        .map((el: ActivatedRouteSnapshot) => el.routeConfig ? el.routeConfig.path : '')
        .filter(str => str.length > 0)
        .join('');


store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void 
    this.handlers[this.getKey(route)] = handle;

【讨论】:

【参考方案4】:

使用这个重用策略

import  ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy  from '@angular/router';
export class CustomReuseStrategy implements RouteReuseStrategy 

  private handlers: [key: string]: DetachedRouteHandle = ;


  constructor() 

  

  shouldDetach(route: ActivatedRouteSnapshot): boolean 
    return true;
  

  store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void 
    this.handlers[route.url.join("/") || route.parent.url.join("/")] = handle;
  

  shouldAttach(route: ActivatedRouteSnapshot): boolean 
    return !!this.handlers[route.url.join("/") || route.parent.url.join("/")];
  

  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle 
    return this.handlers[route.url.join("/") || route.parent.url.join("/")];
  

  shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean 
    return future.routeConfig === curr.routeConfig;
  


【讨论】:

它也适用于延迟加载的子路由,谢谢! 它不会在注销时清除处理程序,我会在主页上获得“/dashboard”路由的快照。有没有办法解决这个问题? @VIshalJain,没有看到你的路由结构,很难诊断出发生了什么。您的应用程序中是否有多个“/dashboard”子路径?这是我在上面的代码中看到的一个潜在陷阱。至于注销时清除的处理程序(DetachedRouteHandle s):从路由器您可以访问路由重用策略,您可以将其转换为自定义重用策略的类型并调用您添加的方法来清除处理程序数组期间登出。由于句柄是不透明的,不确定如何强制 ngOnDestroy()。我的建议:在注销结束时执行浏览器刷新。 其实我自己简单地尝试了这个策略,它似乎有存储句柄的危险 ` //lazy-routing.module.ts ... path: '', component: LazyComponent, ` 在与路由树 // app-routing.module.ts ... path: 'lazy_route', loadChildren: 'app/+lazy/lazy.module#LazyModule', 中的父级相同的键下,这会导致 Error: Cannot reattach ActivatedRouteSnapshot created from a different route,我认为 OP 和未来的读者希望避免这种情况。其他人可以确认吗?【参考方案5】:

使用此自定义重用策略文件进行延迟模块加载

import  ActivatedRouteSnapshot, RouteReuseStrategy, DetachedRouteHandle  from '@angular/router';

/** Interface for object which can store both:
 * An ActivatedRouteSnapshot, which is useful for determining whether or not you should attach a route (see this.shouldAttach)
 * A DetachedRouteHandle, which is offered up by this.retrieve, in the case that you do want to attach the stored route
 */
interface RouteStorageObject 
    snapshot: ActivatedRouteSnapshot;
    handle: DetachedRouteHandle;


export class CustomReuseStrategy implements RouteReuseStrategy 

    handlers: [key: string]: DetachedRouteHandle = ;

    shouldDetach(route: ActivatedRouteSnapshot): boolean 
        console.debug('CustomReuseStrategy:shouldDetach', route);
        return !!route.data && !!(route.data as any).shouldDetach;
    

    store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void 
        console.debug('CustomReuseStrategy:store', route, handle);
        this.handlers[route.data['key']]= handle;
    

    shouldAttach(route: ActivatedRouteSnapshot): boolean 
        console.debug('CustomReuseStrategy:shouldAttach', route);
        return !!route.data && !!this.handlers[route.data['key']];
    

    retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle 
        console.debug('CustomReuseStrategy:retrieve', route);
        if (!route.data) return null;
        return this.handlers[route.data['key']];
    

    shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean 
        console.debug('CustomReuseStrategy:shouldReuseRoute', future, curr);
        return future.data === curr.data;
    


【讨论】:

以上是关于Angular2 无法使用延迟模块加载的自定义重用策略的主要内容,如果未能解决你的问题,请参考以下文章

Angular2延迟加载模块错误'找不到模块'

默认加载自定义安装的 PHP

如何处理 angular2 延迟加载路由失败

LayUi创建一个自定义通用模块

Angular 2 延迟加载技术

用于无类型 npm 模块的 TypeScript 自定义声明文件