Answers:
嗨,安德斯,很好的问题!
我有几乎与您相同的用例,并且想做同样的事情!用户搜索>获取结果>用户导航到结果>用户导航> BOOM 迅速恢复结果,但是您不希望存储用户导航到的特定结果。
tl; dr
您需要具有一个类,该类在中实现RouteReuseStrategy
并提供您的策略ngModule
。如果要在存储路径时进行修改,请修改shouldDetach
功能。返回时true
,Angular将存储路线。如果要在连接路由时进行修改,请修改shouldAttach
功能。当shouldAttach
返回true时,Angular将使用存储的路线代替请求的路线。这是一个Plunker,供您试用。
关于RouteReuseStrategy
通过问这个问题,您已经了解到RouteReuseStrategy允许您告诉Angular 不要破坏组件,而实际上是保存它以便以后重新渲染。这很酷,因为它允许:
如果您想暂时离开某个页面,即使用户在其中输入了很多文本,那么最后一个页面也很重要。企业应用程序会喜欢此功能,因为它过多表单数量!
这就是我想出的解决问题的方法。如您所说,您需要利用RouteReuseStrategy
3.4.1及更高版本中@ angular / router提供的功能。
去做
第一请确保您的项目具有@ angular / router 3.4.1或更高版本。
接下来,创建一个文件来存放要实现的类RouteReuseStrategy
。我打电话给我reuse-strategy.ts
,并将其放在/app
文件夹中以进行保管。现在,此类应如下所示:
import { RouteReuseStrategy } from '@angular/router';
export class CustomReuseStrategy implements RouteReuseStrategy {
}
(不必担心您的TypeScript错误,我们将解决所有问题)
通过为您的课程提供基础知识来完成基础工作app.module
。请注意,您尚未编写CustomReuseStrategy
,但是应该import
从头开始reuse-strategy.ts
。也import { RouteReuseStrategy } from '@angular/router';
@NgModule({
[...],
providers: [
{provide: RouteReuseStrategy, useClass: CustomReuseStrategy}
]
)}
export class AppModule {
}
最后一部分是编写类,该类将控制是否分离,存储,检索和重新连接路由。在我理解旧的复制/粘贴之前,我将在这里对机械进行简短的解释。请参考以下代码,了解我正在描述的方法,当然,代码中有很多文档。
shouldReuseRoute
会触发。这对我来说有点奇怪,但是如果返回true
,那么它实际上会重用您当前使用的路由,并且不会触发其他任何方法。如果用户正在导航,我只会返回false。shouldReuseRoute
返回false
,则shouldDetach
触发。shouldDetach
确定您是否要存储路线,并返回一个boolean
指示。这是您应该决定存储/不存储路径的地方,我可以通过检查要存储的路径数组来做到这一点route.routeConfig.path
,如果path
数组中不存在false,则返回false 。shouldDetach
return true
,将store
被触发,这是您存储有关路线的任何信息的机会。无论您做什么,都需要存储,DetachedRouteHandle
因为Angular稍后会使用它来标识已存储的组件。在下面,我将DetachedRouteHandle
和都存储ActivatedRouteSnapshot
到类的局部变量中。因此,我们已经了解了存储的逻辑,但是导航到组件又如何呢?Angular如何决定拦截您的导航并将已存储的导航放置在原处?
shouldReuseRoute
返回后false
,shouldAttach
运行,这是您确定是否要重新生成或使用内存中组件的机会。如果要重用已存储的组件,请返回true
,一切顺利!DetachedRouteHandle
从返回该组件来进行指示retrieve
。这几乎就是您需要的所有逻辑!在reuse-strategy.ts
下面的代码中,我还为您提供了一个比较两个对象的漂亮函数。我用它来比较将来的路线route.params
和route.queryParams
已存储的路线。如果所有这些都匹配,我想使用存储的组件,而不是生成一个新组件。但是,如何操作取决于您!
重用策略
/**
* reuse-strategy.ts
* by corbfon 1/6/17
*/
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 {
/**
* Object which will store RouteStorageObjects indexed by keys
* The keys will all be a path (as in route.routeConfig.path)
* This allows us to see if we've got a route stored for the requested path
*/
storedRoutes: { [key: string]: RouteStorageObject } = {};
/**
* Decides when the route should be stored
* If the route should be stored, I believe the boolean is indicating to a controller whether or not to fire this.store
* _When_ it is called though does not particularly matter, just know that this determines whether or not we store the route
* An idea of what to do here: check the route.routeConfig.path to see if it is a path you would like to store
* @param route This is, at least as I understand it, the route that the user is currently on, and we would like to know if we want to store it
* @returns boolean indicating that we want to (true) or do not want to (false) store that route
*/
shouldDetach(route: ActivatedRouteSnapshot): boolean {
let detach: boolean = true;
console.log("detaching", route, "return: ", detach);
return detach;
}
/**
* Constructs object of type `RouteStorageObject` to store, and then stores it for later attachment
* @param route This is stored for later comparison to requested routes, see `this.shouldAttach`
* @param handle Later to be retrieved by this.retrieve, and offered up to whatever controller is using this class
*/
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
let storedRoute: RouteStorageObject = {
snapshot: route,
handle: handle
};
console.log( "store:", storedRoute, "into: ", this.storedRoutes );
// routes are stored by path - the key is the path name, and the handle is stored under it so that you can only ever have one object stored for a single path
this.storedRoutes[route.routeConfig.path] = storedRoute;
}
/**
* Determines whether or not there is a stored route and, if there is, whether or not it should be rendered in place of requested route
* @param route The route the user requested
* @returns boolean indicating whether or not to render the stored route
*/
shouldAttach(route: ActivatedRouteSnapshot): boolean {
// this will be true if the route has been stored before
let canAttach: boolean = !!route.routeConfig && !!this.storedRoutes[route.routeConfig.path];
// this decides whether the route already stored should be rendered in place of the requested route, and is the return value
// at this point we already know that the paths match because the storedResults key is the route.routeConfig.path
// so, if the route.params and route.queryParams also match, then we should reuse the component
if (canAttach) {
let willAttach: boolean = true;
console.log("param comparison:");
console.log(this.compareObjects(route.params, this.storedRoutes[route.routeConfig.path].snapshot.params));
console.log("query param comparison");
console.log(this.compareObjects(route.queryParams, this.storedRoutes[route.routeConfig.path].snapshot.queryParams));
let paramsMatch: boolean = this.compareObjects(route.params, this.storedRoutes[route.routeConfig.path].snapshot.params);
let queryParamsMatch: boolean = this.compareObjects(route.queryParams, this.storedRoutes[route.routeConfig.path].snapshot.queryParams);
console.log("deciding to attach...", route, "does it match?", this.storedRoutes[route.routeConfig.path].snapshot, "return: ", paramsMatch && queryParamsMatch);
return paramsMatch && queryParamsMatch;
} else {
return false;
}
}
/**
* Finds the locally stored instance of the requested route, if it exists, and returns it
* @param route New route the user has requested
* @returns DetachedRouteHandle object which can be used to render the component
*/
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
// return null if the path does not have a routerConfig OR if there is no stored route for that routerConfig
if (!route.routeConfig || !this.storedRoutes[route.routeConfig.path]) return null;
console.log("retrieving", "return: ", this.storedRoutes[route.routeConfig.path]);
/** returns handle when the route.routeConfig.path is already stored */
return this.storedRoutes[route.routeConfig.path].handle;
}
/**
* Determines whether or not the current route should be reused
* @param future The route the user is going to, as triggered by the router
* @param curr The route the user is currently on
* @returns boolean basically indicating true if the user intends to leave the current route
*/
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
console.log("deciding to reuse", "future", future.routeConfig, "current", curr.routeConfig, "return: ", future.routeConfig === curr.routeConfig);
return future.routeConfig === curr.routeConfig;
}
/**
* This nasty bugger finds out whether the objects are _traditionally_ equal to each other, like you might assume someone else would have put this function in vanilla JS already
* One thing to note is that it uses coercive comparison (==) on properties which both objects have, not strict comparison (===)
* Another important note is that the method only tells you if `compare` has all equal parameters to `base`, not the other way around
* @param base The base object which you would like to compare another object to
* @param compare The object to compare to base
* @returns boolean indicating whether or not the objects have all the same properties and those properties are ==
*/
private compareObjects(base: any, compare: any): boolean {
// loop through all properties in base object
for (let baseProperty in base) {
// determine if comparrison object has that property, if not: return false
if (compare.hasOwnProperty(baseProperty)) {
switch(typeof base[baseProperty]) {
// if one is object and other is not: return false
// if they are both objects, recursively call this comparison function
case 'object':
if ( typeof compare[baseProperty] !== 'object' || !this.compareObjects(base[baseProperty], compare[baseProperty]) ) { return false; } break;
// if one is function and other is not: return false
// if both are functions, compare function.toString() results
case 'function':
if ( typeof compare[baseProperty] !== 'function' || base[baseProperty].toString() !== compare[baseProperty].toString() ) { return false; } break;
// otherwise, see if they are equal using coercive comparison
default:
if ( base[baseProperty] != compare[baseProperty] ) { return false; }
}
} else {
return false;
}
}
// returns true only after false HAS NOT BEEN returned through all loops
return true;
}
}
行为
此实现将用户访问的每个唯一路由准确地存储在路由器上一次。在站点上的整个用户会话中,这将继续添加到存储在内存中的组件中。如果您想限制您存储的路线,则可以使用该shouldDetach
方法。它控制着您保存的路由。
例
假设您的用户从首页中搜索了一些内容,然后将其导航到该路径search/:term
,该路径可能显示为www.yourwebsite.com/search/thingsearchedfor
。搜索页面包含一堆搜索结果。您想存储这条路线,以防他们想回来!现在,他们点击一个搜索结果,并获得导航到view/:resultId
,你不希望店,看到他们很可能会出现一次。完成上述实现后,我只需更改shouldDetach
方法即可!可能是这样的:
首先,让我们创建一个要存储的路径数组。
private acceptedRoutes: string[] = ["search/:term"];
现在,shouldDetach
我们可以route.routeConfig.path
对照数组检查。
shouldDetach(route: ActivatedRouteSnapshot): boolean {
// check to see if the route's path is in our acceptedRoutes array
if (this.acceptedRoutes.indexOf(route.routeConfig.path) > -1) {
console.log("detaching", route);
return true;
} else {
return false; // will be "view/:resultId" when user navigates to result
}
}
由于Angular 仅存储路线的一个实例,因此该存储将是轻量级的,并且我们将仅存储位于以下位置的组件search/:term
而不是所有其他!
附加链接
尽管目前没有太多的文档,但是这里有一些指向存在的链接:
Angular Docs:https : //angular.io/docs/ts/latest/api/router/index/RouteReuseStrategy-class.html
简介文章:https : //www.softwarearchitekt.at/post/2016/12/02/sticky-routes-in-angular-2-3-with-routereusestrategy.aspx
nativescript棱角的默认实现RouteReuseStrategy:https://github.com/NativeScript/nativescript-angular/blob/cb4fd3a/nativescript-angular/router/ns-route-reuse-strategy.ts
Observable
。该组件应Observable
在ngOnInit
生命周期挂钩中进行预订。然后,您将能够从中告诉组件ReuseRouteStrategy
它刚刚被连接,并且组件可以根据需要修改其状态。
不要被接受的答案吓倒,这很简单。这是您需要的快速答案。我建议至少阅读已接受的答案,因为它非常详细。
此解决方案不会像接受的答案那样进行任何参数比较,但对于存储一组路由会很好用。
app.module.ts导入:
import { RouteReuseStrategy } from '@angular/router';
import { CustomReuseStrategy, Routing } from './shared/routing';
@NgModule({
//...
providers: [
{ provide: RouteReuseStrategy, useClass: CustomReuseStrategy },
]})
共享/路由:
export class CustomReuseStrategy implements RouteReuseStrategy {
routesToCache: string[] = ["dashboard"];
storedRouteHandles = new Map<string, DetachedRouteHandle>();
// Decides if the route should be stored
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return this.routesToCache.indexOf(route.routeConfig.path) > -1;
}
//Store the information for the route we're destructing
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
this.storedRouteHandles.set(route.routeConfig.path, handle);
}
//Return true if we have a stored route object for the next route
shouldAttach(route: ActivatedRouteSnapshot): boolean {
return this.storedRouteHandles.has(route.routeConfig.path);
}
//If we returned true in shouldAttach(), now return the actual route data for restoration
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
return this.storedRouteHandles.get(route.routeConfig.path);
}
//Reuse the route if we're going to and from the same route
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
}
除了接受的答案(由Corbfon提出)和Chris Fremgen简短而直接的解释之外,我还想添加一种更灵活的方法来处理应该使用重用策略的路由。
这两个答案都将我们要缓存的路由存储在数组中,然后检查当前路由路径是否在数组中。此检查是在shouldDetach
方法中完成的。
我发现这种方法不灵活,因为如果我们想更改路线的名称,我们需要记住还要在我们的CustomReuseStrategy
班级中更改路线的名称。我们可能会忘记更改它,或者我们团队中的其他开发人员可能决定更改路线名称,甚至不知道的存在RouteReuseStrategy
。
无需将要缓存的路由存储在数组中,我们可以直接在RouterModule
using data
对象中对其进行标记。这样,即使我们更改了路由名称,重用策略仍将适用。
{
path: 'route-name-i-can-change',
component: TestComponent,
data: {
reuseRoute: true
}
}
然后在shouldDetach
方法中我们利用了这一点。
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return route.data.reuseRoute === true;
}
要将Chris Fremgen的策略与延迟加载的模块一起使用,请将CustomReuseStrategy类修改为以下内容:
import {ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy} from '@angular/router';
export class CustomReuseStrategy implements RouteReuseStrategy {
routesToCache: string[] = ["company"];
storedRouteHandles = new Map<string, DetachedRouteHandle>();
// Decides if the route should be stored
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return this.routesToCache.indexOf(route.data["key"]) > -1;
}
//Store the information for the route we're destructing
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
this.storedRouteHandles.set(route.data["key"], handle);
}
//Return true if we have a stored route object for the next route
shouldAttach(route: ActivatedRouteSnapshot): boolean {
return this.storedRouteHandles.has(route.data["key"]);
}
//If we returned true in shouldAttach(), now return the actual route data for restoration
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
return this.storedRouteHandles.get(route.data["key"]);
}
//Reuse the route if we're going to and from the same route
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
}
最后,在功能模块的路由文件中,定义密钥:
{ path: '', component: CompanyComponent, children: [
{path: '', component: CompanyListComponent, data: {key: "company"}},
{path: ':companyID', component: CompanyDetailComponent},
]}
更多信息在这里。
route.data["key"]
构建而没有错误。但是我遇到的问题是我有一个在两个不同地方使用的route +组件。1. sample/list/item
而2. product/id/sample/list/item
当我第一次加载任何的路径,它加载罚款,但其他投重新连接错误,因为我是基于存储list/item
所以我的解决办法是我复制的路线,并提出了一些变化的URL路径,但显示相同的组件。不知道是否还有其他解决方法。
另一个实现更有效,完整和可重用。这个支持@UğurDinç等惰性加载模块,并集成@Davor路由数据标志。最好的改进是基于页面绝对路径自动生成(几乎)唯一标识符。这样,您不必自己在每个页面上进行定义。
标记任何要缓存的页面设置reuseRoute: true
。将在shouldDetach
方法中使用。
{
path: '',
component: MyPageComponent,
data: { reuseRoute: true },
}
这是最简单的策略实现,无需比较查询参数。
import { ActivatedRouteSnapshot, RouteReuseStrategy, DetachedRouteHandle, UrlSegment } from '@angular/router'
export class CustomReuseStrategy implements RouteReuseStrategy {
storedHandles: { [key: string]: DetachedRouteHandle } = {};
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return route.data.reuseRoute || false;
}
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
const id = this.createIdentifier(route);
if (route.data.reuseRoute) {
this.storedHandles[id] = handle;
}
}
shouldAttach(route: ActivatedRouteSnapshot): boolean {
const id = this.createIdentifier(route);
const handle = this.storedHandles[id];
const canAttach = !!route.routeConfig && !!handle;
return canAttach;
}
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
const id = this.createIdentifier(route);
if (!route.routeConfig || !this.storedHandles[id]) return null;
return this.storedHandles[id];
}
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
private createIdentifier(route: ActivatedRouteSnapshot) {
// Build the complete path from the root to the input route
const segments: UrlSegment[][] = route.pathFromRoot.map(r => r.url);
const subpaths = ([] as UrlSegment[]).concat(...segments).map(segment => segment.path);
// Result: ${route_depth}-${path}
return segments.length + '-' + subpaths.join('/');
}
}
这也比较了查询参数。compareObjects
与@Corbfon版本相比有一点改进:遍历基础对象和比较对象的属性。请记住,您可以使用外部且更可靠的实现,例如lodash isEqual
方法。
import { ActivatedRouteSnapshot, RouteReuseStrategy, DetachedRouteHandle, UrlSegment } from '@angular/router'
interface RouteStorageObject {
snapshot: ActivatedRouteSnapshot;
handle: DetachedRouteHandle;
}
export class CustomReuseStrategy implements RouteReuseStrategy {
storedRoutes: { [key: string]: RouteStorageObject } = {};
shouldDetach(route: ActivatedRouteSnapshot): boolean {
return route.data.reuseRoute || false;
}
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
const id = this.createIdentifier(route);
if (route.data.reuseRoute && id.length > 0) {
this.storedRoutes[id] = { handle, snapshot: route };
}
}
shouldAttach(route: ActivatedRouteSnapshot): boolean {
const id = this.createIdentifier(route);
const storedObject = this.storedRoutes[id];
const canAttach = !!route.routeConfig && !!storedObject;
if (!canAttach) return false;
const paramsMatch = this.compareObjects(route.params, storedObject.snapshot.params);
const queryParamsMatch = this.compareObjects(route.queryParams, storedObject.snapshot.queryParams);
console.log('deciding to attach...', route, 'does it match?');
console.log('param comparison:', paramsMatch);
console.log('query param comparison', queryParamsMatch);
console.log(storedObject.snapshot, 'return: ', paramsMatch && queryParamsMatch);
return paramsMatch && queryParamsMatch;
}
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
const id = this.createIdentifier(route);
if (!route.routeConfig || !this.storedRoutes[id]) return null;
return this.storedRoutes[id].handle;
}
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
private createIdentifier(route: ActivatedRouteSnapshot) {
// Build the complete path from the root to the input route
const segments: UrlSegment[][] = route.pathFromRoot.map(r => r.url);
const subpaths = ([] as UrlSegment[]).concat(...segments).map(segment => segment.path);
// Result: ${route_depth}-${path}
return segments.length + '-' + subpaths.join('/');
}
private compareObjects(base: any, compare: any): boolean {
// loop through all properties
for (const baseProperty in { ...base, ...compare }) {
// determine if comparrison object has that property, if not: return false
if (compare.hasOwnProperty(baseProperty)) {
switch (typeof base[baseProperty]) {
// if one is object and other is not: return false
// if they are both objects, recursively call this comparison function
case 'object':
if (typeof compare[baseProperty] !== 'object' || !this.compareObjects(base[baseProperty], compare[baseProperty])) {
return false;
}
break;
// if one is function and other is not: return false
// if both are functions, compare function.toString() results
case 'function':
if (typeof compare[baseProperty] !== 'function' || base[baseProperty].toString() !== compare[baseProperty].toString()) {
return false;
}
break;
// otherwise, see if they are equal using coercive comparison
default:
// tslint:disable-next-line triple-equals
if (base[baseProperty] != compare[baseProperty]) {
return false;
}
}
} else {
return false;
}
}
// returns true only after false HAS NOT BEEN returned through all loops
return true;
}
}
如果您有生成唯一密钥的最佳方法,请注释我的答案,我将更新代码。
感谢所有分享解决方案的人。
在我们的案例中,所有提到的解决方案都不足够。我们有以下小型企业应用程序:
我们的要求:
我们路线的简化示例:
const routes: Routes = [{
path: '',
children: [
{
path: '',
canActivate: [CanActivate],
loadChildren: () => import('./modules/dashboard/dashboard.module').then(module => module.DashboardModule)
},
{
path: 'companies',
canActivate: [CanActivate],
loadChildren: () => import('./modules/company/company.module').then(module => module.CompanyModule)
}
]
},
{
path: 'login',
loadChildren: () => import('./modules/login/login.module').then(module => module.LoginModule),
data: {
defaultReuseStrategy: true, // Ignore our custom route strategy
resetReuseStrategy: true // Logout redirect user to login and all data are destroyed
}
}];
重用策略:
export class AppReuseStrategy implements RouteReuseStrategy {
private handles: Map<string, DetachedRouteHandle> = new Map();
// Asks if a snapshot from the current routing can be used for the future routing.
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig;
}
// Asks if a snapshot for the current route already has been stored.
// Return true, if handles map contains the right snapshot and the router should re-attach this snapshot to the routing.
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
if (this.shouldResetReuseStrategy(route)) {
this.deactivateAllHandles();
return false;
}
if (this.shouldIgnoreReuseStrategy(route)) {
return false;
}
return this.handles.has(this.getKey(route));
}
// Load the snapshot from storage. It's only called, if the shouldAttach-method returned true.
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
return this.handles.get(this.getKey(route)) || null;
}
// Asks if the snapshot should be detached from the router.
// That means that the router will no longer handle this snapshot after it has been stored by calling the store-method.
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
return !this.shouldIgnoreReuseStrategy(route);
}
// After the router has asked by using the shouldDetach-method and it returned true, the store-method is called (not immediately but some time later).
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle | null): void {
if (!handle) {
return;
}
this.handles.set(this.getKey(route), handle);
}
private shouldResetReuseStrategy(route: ActivatedRouteSnapshot): boolean {
let snapshot: ActivatedRouteSnapshot = route;
while (snapshot.children && snapshot.children.length) {
snapshot = snapshot.children[0];
}
return snapshot.data && snapshot.data.resetReuseStrategy;
}
private shouldIgnoreReuseStrategy(route: ActivatedRouteSnapshot): boolean {
return route.data && route.data.defaultReuseStrategy;
}
private deactivateAllHandles(): void {
this.handles.forEach((handle: DetachedRouteHandle) => this.destroyComponent(handle));
this.handles.clear();
}
private destroyComponent(handle: DetachedRouteHandle): void {
const componentRef: ComponentRef<any> = handle['componentRef'];
if (componentRef) {
componentRef.destroy();
}
}
private getKey(route: ActivatedRouteSnapshot): string {
return route.pathFromRoot
.map((snapshot: ActivatedRouteSnapshot) => snapshot.routeConfig ? snapshot.routeConfig.path : '')
.filter((path: string) => path.length > 0)
.join('');
}
}
以下是工作!参考:https : //www.cnblogs.com/lovesangel/p/7853364.html
import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';
export class CustomReuseStrategy implements RouteReuseStrategy {
public static handlers: { [key: string]: DetachedRouteHandle } = {}
private static waitDelete: string
public static deleteRouteSnapshot(name: string): void {
if (CustomReuseStrategy.handlers[name]) {
delete CustomReuseStrategy.handlers[name];
} else {
CustomReuseStrategy.waitDelete = name;
}
}
public shouldDetach(route: ActivatedRouteSnapshot): boolean {
return true;
}
public store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
if (CustomReuseStrategy.waitDelete && CustomReuseStrategy.waitDelete == this.getRouteUrl(route)) {
// 如果待删除是当前路由则不存储快照
CustomReuseStrategy.waitDelete = null
return;
}
CustomReuseStrategy.handlers[this.getRouteUrl(route)] = handle
}
public shouldAttach(route: ActivatedRouteSnapshot): boolean {
return !!CustomReuseStrategy.handlers[this.getRouteUrl(route)]
}
/** 从缓存中获取快照,若无则返回nul */
public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
if (!route.routeConfig) {
return null
}
return CustomReuseStrategy.handlers[this.getRouteUrl(route)]
}
public shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
return future.routeConfig === curr.routeConfig &&
JSON.stringify(future.params) === JSON.stringify(curr.params);
}
private getRouteUrl(route: ActivatedRouteSnapshot) {
return route['_routerState'].url.replace(/\//g, '_')
}
}
_routerState
。
_routerState
会造成任何危害?
deleteRouteSnapshot
什么时候打电话?
我在实现自定义路由重用策略时遇到了以下问题:
所以我写了一个图书馆来解决这些问题。该库提供用于附加/分离挂钩的服务和装饰器,并使用路线的组件存储分离的路线,而不是路线的路径。
例:
/* Usage with decorators */
@onAttach()
public onAttach(): void {
// your code...
}
@onDetach()
public onDetach(): void {
// your code...
}
/* Usage with a service */
public ngOnInit(): void {
this.cacheRouteReuse
.onAttach(HomeComponent) // or any route's component
.subscribe(component => {
// your code...
});
this.cacheRouteReuse
.onDetach(HomeComponent) // or any route's component
.subscribe(component => {
// your code...
});
}