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 无法使用延迟模块加载的自定义重用策略的主要内容,如果未能解决你的问题,请参考以下文章